Files
ZYZ/shared/domain/battleField/guildActivity.ts
2021-03-31 21:01:12 +08:00

661 lines
25 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 status = 0; // 活动状态 0-未开始 1-已开始 2-已结束 // TODO 写进const表
public guildList: Array<{ serverId: number, guildCode: string }> = []; // 所有军团
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 getItem(roleId: string) {
return this.items.get(roleId)||[]
}
// 是否加入过
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);
if(this.status == 1) { // TODO 写进const表
let item = getRaceEventItems();
this.handleItems(roleId, sid, item);
}
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));
this.guildList.push({guildCode, serverId});
if(this.status == 1) { // TODO 写进const表
this.woodenHorseStartRace(this.woodenHorses.get(guildCode));
}
}
let woodenHorse = this.woodenHorses.get(guildCode);
let events = this.events.get(guildCode)||[];
let needSendEnd = woodenHorse.calCurWoodenHorse(events);
if(woodenHorse.status == 1 || woodenHorse.status == 2) { // 更新距离 // TODO 写进const表
await setRankWithoutUserInfo(REDIS_KEY.RACE_ACTIVITY, serverId, guildCode, woodenHorse.distance, Math.floor((woodenHorse.time - woodenHorse.startTime)/1000), true, false);
if (needSendEnd) { // 抵达后发送奖励,发送消息,结算
await sendSingleRaceActEndMsg(guildCode, woodenHorse);
}
}
this.handleItemsByWoodenHorse(woodenHorse);
return woodenHorse;
}
public async useItem(fromRoleId: string, sid: string, fromGuild: string, toGuild: string, id: number, count: number) {
let rec = this.handleItems(fromRoleId, sid, [{id, count: -1 * count}]);
if(!rec) return false;
let event = new Event(id, fromGuild, toGuild, count);
if(!this.events.has(toGuild)) {
this.events.set(toGuild, [event]);
} else {
let events = this.events.get(toGuild)||[];
events.push(event);
this.events.set(toGuild, events);
}
let chatSid = await getGuildChannelSid(toGuild);
pinus.app.rpc.chat.guildRemote.sendRaceEvent.toServer(chatSid, toGuild, [event]);
return event;
}
// 定时任务到,开始比赛,设置开始赛道,发放初始道具
public startRace() {
this.status = 1; // TODO 写进const表
let guildCodes = new Array<string>();
for(let [code, woodenHorse] of this.woodenHorses) {
this.woodenHorseStartRace(woodenHorse);
guildCodes.push(code);
}
return guildCodes;
}
private woodenHorseStartRace(woodenHorse: WoodenHorse) {
woodenHorse.status = 1; // TODO 写进const表
woodenHorse.time = Date.now();
woodenHorse.startTime = Date.now();
let members = woodenHorse.members;
for(let { roleId, sid } of members) {
let item = getRaceEventItems();
this.handleItems(roleId, sid, item);
}
}
// 初始进入就随机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, 1, distance);
this.events.get(guildCode).push(event);
} else if (type == RACE_EVENT_TYPE.EVENT) {
let event = new Event(events[index], guildCode, guildCode, 1, 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 handleItemsByWoodenHorse(woodenHorse: WoodenHorse) {
let { members } = woodenHorse;
for(let curMember of members) {
let { roleId, sid, items = [] } = curMember;
if(items.length > 0) this.handleItems(roleId, sid, items);
curMember.items = [];
}
}
private handleItems(roleId: string, sid: string, incItems: {id: number, count: number}[]) {
let items = this.items.get(roleId)||[];
let sendItems = new Array<{id: number, count: number}>();
for(let {id, count: inc} of incItems) {
let curItem = items.find(cur => cur.id == id);
if(!curItem) {
curItem = { id, count: 0 };
items.push(curItem);
}
if(curItem.count + inc < 0 ) return false;
if(inc != 0) {
curItem.count += inc;
sendItems.push({ id, count: curItem.count });
}
}
this.items.set(roleId, items);
let uids = [{uid: roleId, sid}];
pinus.app.get('channelService').pushMessageByUids('onRaceItemUpdate', resResult(STATUS.SUCCESS, { items: sendItems }), uids);
return items;
}
public deleteFromList(guildCode: string) {
let index = this.guildList.findIndex(cur => cur.guildCode == guildCode);
this.guildList.splice(index, 1);
}
}
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 = GUILDACTIVITY.RACE_INIT_SPEED; // 速度
@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;
}
/**
* 根据时间计算当前木马速度距离耐久等
* @param events
* @returns {boolean} needSendEnd 是否跑到终点发送结束新号
*/
public calCurWoodenHorse(events: Event[]): boolean {
console.log('**', JSON.stringify(events))
if(this.status == 2) return false; // TODO 写进const表
if(this.status == 0 && this.stopContinueTime && Date.now() > this.stopContinueTime) {
this.status = 1; this.stopContinueTime = 0;
}
if(this.status == 1) {
if(this.distance >= GUILDACTIVITY.RACEACTIVITY_LENGTH) {
this.distance = GUILDACTIVITY.RACEACTIVITY_LENGTH;
this.status = 2;
return true;
}
console.log('*********', this.distance, Date.now(), this.speed)
this.distance = Math.floor((this.distance + (Date.now() - this.time)/1000 * this.speed ) * 1000)/1000; // 1位小数点
this.time = Date.now();
}
let effectiveEvents = new Array<Event>();
let delEvents = new Array<number>();
for(let i = 0; i < events.length; i++) {
let event = events[i];
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) {
if(event.endTime && event.startTime == event.endTime) {
isEffective = true;
}
if(event.endDistance && event.startDistance == event.endDistance) {
isEffective = true;
}
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 = GUILDACTIVITY.RACE_INIT_SPEED + this.memberCnt * GUILDACTIVITY.RACE_PER_SPEED;
for(let { id, count, endTime } of effectiveEvents) {
this.calEvent(id, count, endTime);
}
return false;
}
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.shield = 0;
this.durability -= (count - this.shield) * effect[0];
if(this.durability > 100) this.durability = 100;
if(this.durability < 0) this.durability = 0;
}
}
break;
case RACE_EVENT.GUISHOUYINFU:
if (this.shieldTime < Date.now()) {
this.stopContinueTime = endTime;
this.status = 0; // TODO 写进const表
}
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.JIASU_1:
this.speed *= Math.pow(1 + effect[0] / 100, count); break;
case RACE_EVENT.JIASU_2:
this.speed += effect[0]; break;
case RACE_EVENT.HUIFU_1:
this.durability += effect[0];
if(this.durability > 100) this.durability = 100;
if(this.durability < 0) this.durability = 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];
if(this.durability > 100) this.durability = 100;
if(this.durability < 0) this.durability = 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;
}
if(this.durability <= 0) {
this.status = 0; // TODO 写进const表
this.speed = 0;
}
}
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 {
@prop({required: true})
id: number;
@prop({required: true})
fromGuild: string;
@prop({required: true})
toGuild: string;
@prop({required: true})
startTime?: number;
@prop({required: true})
startDistance?: number;
@prop({required: true})
endTime?: number;
@prop({required: true})
endDistance?: number;
@prop({required: true})
count: number = 1;
constructor(id: number, fromGuild: string, toGuild: string, count?: number, distance?: 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;
}
}