Files
ZYZ/shared/domain/battleField/guildActivity.ts

606 lines
23 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { GUILDACTIVITY } from "../../pubUtils/dicParam";
import { SimpleGuildRankParam, SimpleRoleRankParam, GuildRankParam } from '../rank'
import { prop } from "@typegoose/typegoose";
import { CITY_STATUS, RACE_EVENT_TYPE, RACE_EVENT_EFFECT_TYPE, REDIS_KEY, RACE_EVENT, STATUS } from "../../consts";
import { gameData, getRaceEventItems } from "../../pubUtils/data";
import { GuildModel } from "../../db/Guild";
import { getRandEelm, sortArrRandom, resResult } from "../../pubUtils/util";
import { RoleType } from "../../db/Role";
import { setRank, getMyUnionRank, setRankWithoutUserInfo } from "../../services/redisService";
import { RewardInter } from "../../pubUtils/interface";
import { pinus } from "pinus";
import { homedir } from "os";
import { sendSingleRaceActEndMsg } from "../../services/guildActivityService";
import { getGuildChannelSid } from "../../services/chatService";
export class GateMembersRec {
roleId: string;
round: number = 0;
enemies: number[] = [];
constructor(roleId: string) {
this.roleId = roleId;
}
}
// 军团活动蛮夷入侵城门血量等数据存储
export class GateActivityObject {
private gateHp: Map<string, number> = new Map(); // 城门血条,每个军团有一条血条 guildCode => hp
private members: Map<string, Array<Member>> = new Map(); // 每个军团参与的成员 guildCode => [{roleId, job}]
private membersRecord: Map<string, GateMembersRec> = new Map(); // 每个成员的回合数和敌军数,防刷 recCode => GateMembersRec
private guilds: Map<number, string[]> = new Map(); // 参加的所有军团 server => [guildCode]
public getObj(guildCode: string, serverId: number) {
console.log(guildCode, serverId)
return {
gateHp: this.getGateHpAndInc(guildCode),
members: this.members.get(guildCode)||[],
memberesRecord: [...this.membersRecord],
guilds: this.guilds.get(serverId)||[]
}
}
public getGateHpAndInc(guildCode: string, inc: number = 0) {
let gateHp = this.gateHp.get(guildCode);
if(!this.gateHp.has(guildCode)) {
gateHp = GUILDACTIVITY.GATEACTIVITY_GATEHP;
}
if(inc != 0) {
gateHp += inc;
this.gateHp.set(guildCode, gateHp);
}
if(gateHp <= 0) gateHp = 0;
return gateHp
}
public getGuilds() {
return this.guilds;
}
public pushMembers(guildCode: string, serverId: number, roleId: string, job: number) {
if(this.members.has(guildCode)) {
let members = this.members.get(guildCode);
if(members.findIndex(cur => cur.roleId == roleId) == -1) {
members.push({ roleId, job });
}
} else {
let arr = new Array<string>();
arr.push(roleId);
this.members.set(guildCode, [{ roleId, job }]);
}
if(this.guilds.has(serverId)) {
let arr = this.guilds.get(serverId);
if(!arr.includes(guildCode)) arr.push(guildCode);
this.guilds.set(serverId, arr);
} else {
this.guilds.set(serverId, [guildCode]);
}
}
public getMemberRecord(recCode: string, roleId: string) {
return this.membersRecord.get(recCode)||new GateMembersRec(roleId)
}
public setMemberRecord(recCode: string, newMemberRecord: GateMembersRec) {
this.membersRecord.set(recCode, newMemberRecord);
}
public delMemberRecord(recCode: string) {
this.membersRecord.delete(recCode);
}
public delGuildRecord(guildCode: string, serverId: number) {
let guildList = this.guilds.get(serverId);
if(guildList) {
let index = guildList.indexOf(guildCode);
guildList.splice(index, 1);
}
this.members.delete(guildCode);
}
}
// 军团诸侯混战等数据
export class CityActivityObject {
private gateHp: Map<string, number> = new Map(); // 城门血条每个cityId有一条血条 serverId&cityId => gateHp
private members: Map<string, Array<Member>> = new Map(); // 每个军团参与的成员 guildCode => [{roleId, job}]
private cities: Map<string, string[]> = new Map(); // 各个城池参与的军团 serverId&cityId => [guildCode]
private guilds: Map<string, number> = new Map(); // 军团所在的城池 guildCode => cityId
private historyCity: Map<string, number> = new Map(); // 获取自己打开过的城池的页面 roleId => cityId
private getKey(serverId: number, cityId: number) {
return `${serverId}_${cityId}`;
}
private decodeKey(key: string) {
let arr = key.split('_');
return {
serverId: parseInt(arr[0]),
cityId: parseInt(arr[1])
}
}
public getObj( serverId: number, cityId: number, guildCode: string) {
let key = this.getKey(serverId, cityId);
return {
gateHp: this.gateHp.get(key),
members: this.members.get(guildCode),
city: this.cities.get(key),
guild: this.guilds.get(guildCode)
}
}
public getAllCities() {
let allCities = new Array<{ serverId: number, cityId: number, guildCodes: string[]}>();
let serverlists = new Array<number>();
for(let [key, guildCodes] of this.cities) {
let { serverId, cityId } = this.decodeKey(key);
allCities.push({ serverId, cityId, guildCodes });
if(!serverlists.includes(serverId)) serverlists.push(serverId);
}
return {cities: allCities, serverlists};
}
public getGuildsInCity(serverId: number, cityId: number) {
let key = this.getKey(serverId, cityId);
return this.cities.get(key)||[];
}
public getMembersOfGuild(guildCode: string) {
return this.members.get(guildCode)||[];
}
public getGateHpAndInc(serverId: number, cityId: number, maxHp: number, inc: number = 0) {
let key = this.getKey(serverId, cityId);
let gateHp = this.gateHp.get(key);
if(!this.gateHp.has(key)) {
gateHp = maxHp;
}
if(inc != 0) {
gateHp += inc;
this.gateHp.set(key, gateHp);
}
if(gateHp <= 0) gateHp = 0;
return gateHp
}
public getHistoryCity(roleId: string) {
return this.historyCity.get(roleId)
}
public setHistoryCity(roleId: string, cityId: number) {
return this.historyCity.set(roleId, cityId);
}
public pushMembers(guildCode: string, roleId: string, job: number) {
if(this.members.has(guildCode)) {
let members = this.members.get(guildCode);
if(members.findIndex(cur => cur.roleId == roleId) == -1) {
members.push({ roleId, job });
}
} else {
let arr = new Array<string>();
arr.push(roleId);
this.members.set(guildCode, [{ roleId, job }]);
}
}
public pushGuild(guildCode: string, serverId: number, cityId: number) {
let key = this.getKey(serverId, cityId);
if(!this.cities.has(key)) {
this.cities.set(key, [guildCode]);
} else {
let arr = this.cities.get(key);
if(!arr.includes(guildCode)) {
arr.push(guildCode);
}
}
this.guilds.set(guildCode, cityId);
}
public delCityRecord(cityId: number, serverId: number) {
let key = this.getKey(serverId, cityId);
let guildCodes = this.cities.get(key)||[];
for(let guildCode of guildCodes) {
this.members.delete(guildCode);
this.guilds.delete(guildCode);
}
this.cities.delete(key);
}
}
// 军团诸侯混战等数据
export class RaceActivityObject {
private members: Map<string, Array<Member>> = new Map(); // 每个军团参与的成员 guildCode => [{roleId, job}]
private woodenHorses: Map<string, WoodenHorse> = new Map(); // 每个军团的木牛流马 guildCode => WoodenHorse
private events: Map<string, Event[]> = new Map(); // 每个军团遇到的事件
private items: Map<string, RewardInter[]> = new Map(); // 每个玩家的道具 roleId => [{id, count}]
// 是否加入过
public hasJoin(guildCode: string, roleId: string) {
let member = this.members.get(guildCode)||[];
return member.findIndex(cur => cur.roleId == roleId) != -1;
}
// 加入member
private pushMember(guildCode: string, roleId: string, job: number) {
if(!this.members.has(guildCode)) {
this.members.set(guildCode, []);
}
this.members.get(guildCode).push({roleId, job});
}
public getMembersOfGuild(guildCode: string) {
return this.members.get(guildCode)||[];
}
public getAllWoodenHorses() {
return this.woodenHorses;
}
public async joinWoodenHorse(guildCode: string, roleId: string, roleName: string, serverId: number, sid: string, job: number) {
let woodenHorse = await this.getWoodenHorse(guildCode, serverId);
if(!woodenHorse) return false;
woodenHorse.joinMember(roleId, roleName, sid)
this.pushMember(guildCode, roleId, job);
this.handleItems(woodenHorse);
return woodenHorse;
}
// 获取某个军团的木马状态
public async getWoodenHorse(guildCode: string, serverId: number) {
if(!this.woodenHorses.has(guildCode)) {
this.initEvents(guildCode);
let guild = await GuildModel.findByCode(guildCode, serverId);
if(!guild) return false;
let leader = <RoleType>guild.leader;
let guildRankParam = new GuildRankParam(guild.icon, guild.name, guild.lv, leader);
await setRank(REDIS_KEY.RACE_ACTIVITY, serverId, guild.code, 0, Math.pow(10, 11) - guild.guildCe, guildRankParam, true);
let { name: guildName, guildCe } = guild;
this.woodenHorses.set(guildCode, new WoodenHorse(guildCode, guildName, guildCe, serverId))
}
let woodenHorse = this.woodenHorses.get(guildCode);
let events = this.events.get(guildCode)||[];
woodenHorse.calCurWoodenHorse(events);
if(woodenHorse.status == 1 || woodenHorse.status == 2) { // 更新距离
await setRankWithoutUserInfo(REDIS_KEY.RACE_ACTIVITY, serverId, guildCode, woodenHorse.distance, Math.floor((woodenHorse.time - woodenHorse.startTime)/1000), true, false);
if (woodenHorse.status == 2) { // 抵达后发送奖励,发送消息,结算
await sendSingleRaceActEndMsg(guildCode, woodenHorse);
}
}
this.handleItems(woodenHorse);
return woodenHorse;
}
public async useItem(fromRoleId: string, sid: string, fromGuild: string, toGuild: string, id: number, count: number) {
let rec = this.handleItem(fromRoleId, sid, id, count);
if(!rec) return rec;
let event = new Event(id, fromGuild, toGuild, count);
if(!this.events.has(toGuild)) {
this.events.set(toGuild, [event]);
} else {
this.events.get(toGuild).push(event);
}
let chatSid = await getGuildChannelSid(toGuild);
pinus.app.rpc.chat.guildRemote.sendRaceEvent.toServer(chatSid, toGuild, [event]);
}
// 定时任务到,开始比赛,设置开始赛道,发放初始道具
public startRace() {
let guildCodes = new Array<string>();
for(let [code, woodenHorse] of this.woodenHorses) {
woodenHorse.status = 1;
woodenHorse.time = Date.now();
woodenHorse.startTime = Date.now();
let members = woodenHorse.members;
for(let { roleId, sid } of members) {
let item = getRaceEventItems();
for(let { id, count } of item) {
this.handleItem(roleId, sid, id, count);
}
}
guildCodes.push(code);
}
return guildCodes;
}
// 初始进入就随机9个灵球事件
public initEvents(guildCode: string) {
if(!this.events.get(guildCode)) {
this.events.set(guildCode, []);
}
let dicEncounter = gameData.raceActivityEncounter; // 距离=>事件类型
let goodEventNum = Math.floor(dicEncounter.eventNum/2);
let badEventNum = dicEncounter.eventNum - goodEventNum;
let dicRaceTypes = gameData.raceTypes.get(RACE_EVENT_TYPE.EVENT);
let goodEvents = getRandEelm(dicRaceTypes.get(RACE_EVENT_EFFECT_TYPE.GOOD), goodEventNum);
let badEvents = getRandEelm(dicRaceTypes.get(RACE_EVENT_EFFECT_TYPE.BAD), badEventNum);
let events = sortArrRandom(goodEvents.concat(badEvents));
let index = 0;
for(let [distance, type] of dicEncounter.events) {
if(type == RACE_EVENT_TYPE.ITEM) {
let event = new Event(RACE_EVENT.ITEM, guildCode, guildCode, distance);
this.events.get(guildCode).push(event);
} else if (type == RACE_EVENT_TYPE.EVENT) {
let event = new Event(events[index], guildCode, guildCode, distance);
this.events.get(guildCode).push(event);
index ++;
}
}
}
public getEvents(guildCode: string, distance: number) {
let events = this.events.get(guildCode)||[];
let result = new Array<Event>();
for(let event of events) {
let { endTime, endDistance } = event;
if(endTime) {
if(Date.now() > endTime) continue;
}
if(endDistance) {
if(distance > endDistance) continue;
}
result.push(event);
}
return result;
}
private handleItems(woodenHorse: WoodenHorse) {
let { members } = woodenHorse;
for(let { roleId, sid, items = [] } of members) {
for(let {id, count} of items) {
this.handleItem(roleId, sid, id, count);
}
}
}
private handleItem(roleId: string, sid: string, id: number, inc: number) {
let items = this.items.get(roleId)||[];
let curItem = items.find(cur => cur.id == id);
if(!curItem && inc < 0) return false;
if(!curItem) {
curItem = { id, count: 0 };
items.push(curItem);
}
if(curItem.count + inc < 0 ) return false;
curItem.count += inc;
let uids = [{uid: roleId, sid}];
pinus.app.get('channelService').pushMessageByUids('onRaceItemUpdate', resResult(STATUS.SUCCESS, { items }), uids);
return items;
}
public deleteRecord(guildCode: string) {
let members = this.members.get(guildCode);
this.woodenHorses.delete(guildCode);
this.events.delete(guildCode);
for(let roleId of members) {
this.items.delete(roleId.roleId);
}
this.members.delete(guildCode);
}
}
class WoodenHorseMember {
roleId: string;
roleName: string;
sid: string;
items?: RewardInter[];
}
// 木牛流马
export class WoodenHorse {
@prop({required: true})
serverId: number = 0; // 服务器id
@prop({required: true})
guildCode: string = ""; // 军团code 木马的唯一标识
@prop({required: true})
guildName: string = ""; // 军团名
@prop({required: true})
guildCe: number = 0; // 军团战力
@prop({required: true})
status: number = 0; // 状态 0-停止 1-开启 2-结束
@prop({required: true})
speed: number = 0; // 速度
@prop({required: true})
durability: number = 100; // 耐久度
@prop({required: true})
distance: number = 0; // 距离
@prop({required: true})
startTime: number = 0; // 开始时间
@prop({required: true})
time: number = 0; // 到达时间
@prop({required: true})
memberCnt: number = 0; // 成员人数
@prop({required: true})
members: WoodenHorseMember[] = []; // 成员
@prop({required: true})
shield: number = 0; // 护盾数量
@prop({required: true})
shieldTime: number = 0; // 天师盾符
@prop({required: true})
stopContinueTime: number = 0; // 鬼手阴符
constructor(guildCode: string, guildName: string, guildCe: number, serverId: number) {
this.guildCode = guildCode;
this.guildName = guildName;
this.guildCe = guildCe;
this.serverId = serverId;
}
public calCurWoodenHorse(events: Event[]) {
if(this.status == 0 && this.stopContinueTime && Date.now() > this.stopContinueTime) {
this.status = 1; this.stopContinueTime = 0;
}
if(this.status == 1) {
this.distance += Math.floor((Date.now() - this.time)/1000 * 10 * this.speed)/10; // 1位小数点
this.time = Date.now();
if(this.distance >= GUILDACTIVITY.RACEACTIVITY_LENGTH) {
this.distance = GUILDACTIVITY.RACEACTIVITY_LENGTH;
// TODO发送结束信号
this.status = 2;
return false;
}
}
let effectiveEvents = new Array<Event>();
let delEvents = new Array<number>();
for(let i = 0; i < events.length; i++) {
let event = events[i];
console.log('******', this.distance, event.startDistance, event.endDistance)
if(!event.startTime && event.startDistance && this.distance > event.startDistance) {
let startTime = Date.now() - Math.floor((this.distance - event.startDistance) / this.speed);
event.setStartTime(startTime); // 距离生效的事件的实际生效时间,主要用于速度叠加顺序
}
let isEffective = false;
if(event.startTime <= Date.now() && event.endTime > Date.now()) {
isEffective = true;
} else if (event.startDistance <= this.distance && event.endDistance > this.distance) {
isEffective = true;
} else if (event.endTime < Date.now() || event.endDistance < this.distance) {
delEvents.push(i);
}
if(isEffective) {
effectiveEvents.push(event);
}
}
for(let i of delEvents) events.splice(i, 1); // 删除过期事件
effectiveEvents.sort((a, b) => a.startTime - b.startTime);
this.speed = this.memberCnt * 10;
console.log('******', effectiveEvents.length);
for(let { id, count, endTime } of effectiveEvents) {
this.calEvent(id, count, endTime);
}
return this;
}
private calEvent(id: number, count: number = 1, endTime?: number) {
let { effect } = gameData.raceActivityEvents.get(id);
switch (id) {
case RACE_EVENT.LIANNU:
if (this.shieldTime > Date.now()) {
if (this.shield >= count) {
this.shield -= count;
} else {
this.durability -= (count - this.shield) * effect[0];
}
}
break;
case RACE_EVENT.GUISHOUYINFU:
if (this.shieldTime > Date.now()) {
this.stopContinueTime = endTime;
this.status = 0;
}
break;
case RACE_EVENT.FENGCHE:
case RACE_EVENT.WUGUIBANYUNFU:
this.speed *= Math.pow(1 + effect[0] / 100, count); break;
case RACE_EVENT.LUDUN:
this.shield += count * effect[0]; break;
case RACE_EVENT.TIANSHIDUNFU:
this.shieldTime = endTime; break;
case RACE_EVENT.JIANSU_1:
this.speed *= 1 + effect[0]; break;
case RACE_EVENT.JIANSU_2:
this.speed += effect[0]; break;
case RACE_EVENT.HUIFU_1:
this.durability += effect[0]; break;
case RACE_EVENT.JIANSU_1:
this.speed *= Math.pow(1 - effect[0] / 100, count); break;
case RACE_EVENT.JIANSU_2:
this.speed -= effect[0]; break;
case RACE_EVENT.SHANGHAI_1:
this.durability -= effect[0]; break;
case RACE_EVENT.ITEM:
let ranMember: WoodenHorseMember[] = getRandEelm(this.members, GUILDACTIVITY.RACEACTIVITY_EVENT_MEMBERCNT);
if(ranMember.length <= 0) ranMember = this.members;
for(let obj of ranMember) {
let item = gameData.raceEventItems;
obj.items = obj.items.concat(item);
}
for(let obj of this.members) {
let item = getRaceEventItems();
obj.items = obj.items.concat(item);
}
break;
}
}
public joinMember(roleId: string, roleName: string, sid: string) {
if(this.members.findIndex(cur => cur.roleId == roleId) == -1) {
this.members.push({ roleId, roleName, sid });
this.speed++;
this.memberCnt++;
}
return this;
}
}
export class Event {
id: number;
fromGuild: string;
toGuild: string;
startTime?: number;
startDistance?: number;
endTime?: number;
endDistance?: number;
count: number = 1;
constructor(id: number, fromGuild: string, toGuild: string, distance?: number, count?: number) {
let dicEvent = gameData.raceActivityEvents.get(id);
this.id = id;
this.fromGuild = fromGuild;
this.toGuild = toGuild;
if(distance) {
this.startDistance = distance;
this.endDistance = this.startDistance + dicEvent.continueDistance;
}
if(dicEvent.effectTime) {
this.startTime = Date.now() + dicEvent.effectTime * 1000;
this.endTime = this.startTime + dicEvent.continueTime * 1000;
}
if(count) {
this.count = count;
}
}
setStartTime(time: number) {
this.startTime = time;
}
}
export interface GuildRankParams {
guildRank: SimpleGuildRankParam[],
myGuildRank: SimpleGuildRankParam,
memberRank?: SimpleRoleRankParam[],
myMemberRank?: SimpleRoleRankParam
}
export class Member {
@prop({required: true})
roleId: string; // 玩家id
@prop({required: true})
job: number; // 在军团的职位
}
export class CityParam {
cityId: number = 0; // 城池id
guardGuildCode: string = ''; // 占领军团id
guardGuildName: string = ''; // 占领军团名
declareCount: number = 0; // 宣战数
status: number = CITY_STATUS.NOT_OPEN; // 城池对于我军状态
constructor(cityId: number) {
this.cityId = cityId;
}
}