Files
ZYZ/game-server/app/services/guildActivity/raceActivityObj.ts

413 lines
16 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 { Member, GateMembersRec, WoodenHorse, Event, WoodenHorseMember, RaceActivityRankParam } from "../../domain/battleField/guildActivity";
import { RewardInter } from "../../pubUtils/interface";
import { getRaceEventItems, gameData } from "../../pubUtils/data";
import { GuildModel } from "../../db/Guild";
import { sendSingleRaceActEndMsg } from "./guildActivityService";
import { REDIS_KEY, RACE_EVENT_TYPE, RACE_EVENT_EFFECT_TYPE, RACE_EVENT, STATUS, PUSH_ROUTE, GUILD_ACTIVITY_STATUS, DEBUG_MAGIC_WORD } from "../../consts";
import { getRandEelm, sortArrRandom, resResult, getRandResultByMember } from "../../pubUtils/util";
import { sendMessageToGuildWithSuc, sendMessageToServerWithSuc, sendMessageToUserWithSuc } from "../pushService";
class MemberInfo extends Member {
isQuit: boolean = false;
constructor(roleId: string, job: number, code: string) {
super();
this.roleId = roleId;
this.job = job;
this.code = code;
}
public quit() {
this.isQuit = true;
}
}
class GuildInfo {
serverId: number;
guildCode: string;
isDissmiss: boolean = false;
constructor(serverId: number, guildCode: string) {
this.serverId = serverId;
this.guildCode = guildCode;
}
dismiss() {
this.isDissmiss = true;
}
}
// 粮草先行
export class RaceActivityObject {
public status = GUILD_ACTIVITY_STATUS.WAITING; // 活动状态 0-未开始 1-已开始 2-已结束
private allStartTime = 0; // 开启时间每天晚上8点
private guildList: GuildInfo[] = []; // 所有军团
private members: Map<string, MemberInfo[]> = 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}]
private hasSentGuild: string[] = [];
public getItem(roleId: string) {
return this.items.get(roleId)||[]
}
// 是否加入过
public getMember(guildCode: string, roleId: string) {
let member = this.members.get(guildCode)||[];
return member.find(cur => cur.roleId == roleId);
}
public async updateMemberSid(guildCode: string, serverId: number, roleId: string, sid: string) {
let member = this.getMember(guildCode, roleId);
if(!member) return member;
let wh = await this.getWoodenHorse(guildCode, serverId);
wh.updateMemberSid(roleId, sid);
return member
}
public async memberLeave(guildCode: string, serverId: number, roleId: string) {
let member = this.getMember(guildCode, roleId);
if(!member) return member;
let wh = await this.getWoodenHorse(guildCode, serverId);
wh.leaveMemberSid(roleId);
return member
}
public async memberQuit(guildCode: string, serverId: number, roleId: string) {
let member = this.getMember(guildCode, roleId);
if(!member) return;
member.quit();
let wh = await this.getWoodenHorse(guildCode, serverId);
wh.leaveMemberSid(roleId, true);
}
public dismiss(guildCode: string) {
let guild = this.guildList.find(guild => guild.guildCode == guildCode);
if(!guild) return;
guild.dismiss();
this.woodenHorses.delete(guildCode);
}
// 加入member
private pushMember(guildCode: string, roleId: string, job: number, code: string) {
if(!this.members.has(guildCode)) {
this.members.set(guildCode, []);
}
this.members.get(guildCode).push(new MemberInfo(roleId, job, code));
}
public getGuilds() {
return this.guildList.filter(cur => !cur.isDissmiss);
}
public getMembersOfGuild(guildCode: string) {
let members = this.members.get(guildCode)||[];
return members.filter(cur => !cur.isQuit);
}
public getAllWoodenHorses() {
return this.woodenHorses;
}
public async getRanks(serverId: number, guildCode?: string) {
let myRank: RaceActivityRankParam = null;
let ranks: RaceActivityRankParam[] = [];
let myIndex = -1;
for(let [_, _wh] of this.woodenHorses) {
if(_wh.serverId == serverId && _wh.status != GUILD_ACTIVITY_STATUS.WAITING) {
let wh = await this.getWoodenHorse(_wh.guildCode, _wh.serverId);
if(wh) {
ranks.push(new RaceActivityRankParam(wh));
}
}
}
ranks.sort((a, b) => {
if(a.sortDistance == b.sortDistance) {
return a.sortTime - b.sortTime;
} else {
return b.sortDistance - a.sortDistance;
}
}).map((wh, index) => {
wh.setRank(index + 1);
if(guildCode && wh.code == guildCode) {
myRank = wh;
myIndex = index;
}
return wh
});
if(!myRank && guildCode) {
let myWoodenHorse = await this.getWoodenHorse(guildCode, serverId);
if(myWoodenHorse) myRank = new RaceActivityRankParam(myWoodenHorse);
}
return { guildRank: ranks, myGuildRank: myRank, myIndex }
}
public async joinWoodenHorse(guildCode: string, roleId: string, roleName: string, serverId: number, sid: string, job: number, code: string, isDebug = false) {
let woodenHorse = await this.getWoodenHorse(guildCode, serverId, isDebug);
if(!woodenHorse) return false;
woodenHorse.joinMember(roleId, roleName, sid, code)
this.pushMember(guildCode, roleId, job, code);
if(this.status == GUILD_ACTIVITY_STATUS.START) {
// this.sendRandItemsToMembers([member], woodenHorse, woodenHorse.remainItems);
this.woodenHorseStartRace(woodenHorse);
}
return await this.getWoodenHorse(guildCode, serverId);
}
// 获取某个军团的木马状态
public async getWoodenHorse(guildCode: string, serverId: number, isDebug: boolean = false) {
if(!this.woodenHorses.has(guildCode)) {
this.initEvents(guildCode);
if(isDebug) {
this.woodenHorses.set(guildCode, new WoodenHorse(guildCode, guildCode, 0, serverId, this.allStartTime, false));
this.guildList.push(new GuildInfo(serverId, guildCode));
} else {
let guild = await GuildModel.findByCode(guildCode, serverId);
if(!guild) return undefined;
let { name: guildName, guildCe } = guild;
this.woodenHorses.set(guildCode, new WoodenHorse(guildCode, guildName, guildCe, serverId, this.allStartTime, false));
this.guildList.push(new GuildInfo(serverId, guildCode));
}
}
let woodenHorse = this.woodenHorses.get(guildCode);
let events = this.events.get(guildCode)||[];
let needSendEnd = woodenHorse.calCurWoodenHorse(events);
if (needSendEnd) { // 抵达后发送奖励,发送消息,结算
await sendSingleRaceActEndMsg(guildCode, woodenHorse);
}
this.handleItemsByWoodenHorse(woodenHorse);
return woodenHorse;
}
public async useItem(serverId: number, fromRoleId: string, sid: string, fromGuild: string, toGuild: string, id: number, count: number, debug = false) {
if(!debug) {
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 { guildRank, myGuildRank, myIndex } = await this.getRanks(serverId, toGuild);
if(myGuildRank) {
let ranks = this.getScreenHorseRanks(guildRank, myIndex);
for(let rank of ranks||[]) {
if(rank) await sendMessageToGuildWithSuc(rank.code, PUSH_ROUTE.GUILD_RACE_EVENT, { timestamp: Date.now(), events: [event] });
}
let timeout = setTimeout(async () => {
await this.getScreenHorses(serverId, guildRank, myIndex, true);
clearTimeout(timeout);
}, event.startTime - Date.now())
} else {
await sendMessageToGuildWithSuc(toGuild, PUSH_ROUTE.GUILD_RACE_EVENT, { timestamp: Date.now(), events: [event] });
}
return event;
}
// 定时任务到,开始比赛,设置开始赛道,发放初始道具
public startRace() {
this.status = GUILD_ACTIVITY_STATUS.START;
if(this.allStartTime == 0) this.allStartTime = Date.now();
let guildCodes = new Array<string>();
for(let [code, woodenHorse] of this.woodenHorses) {
if(woodenHorse.memberCnt > 0) {
this.woodenHorseStartRace(woodenHorse);
guildCodes.push(code);
}
}
return guildCodes;
}
public stopRace() {
this.status = GUILD_ACTIVITY_STATUS.END;
for(let [_, woodenHorse] of this.woodenHorses) {
woodenHorse.stopRace();
}
}
private woodenHorseStartRace(woodenHorse: WoodenHorse) {
woodenHorse.startRace(this.allStartTime);
let members = woodenHorse.members;
let normalItems = getRaceEventItems();
this.sendRandItemsToMembers(members, woodenHorse, normalItems);
}
private sendRandItemsToMembers(members: WoodenHorseMember[], woodenHorse: WoodenHorse, items: Map<number, { total: number, max: number}>) {
let notReceiveMembers = members.filter(member => !member.isReceived() && member.isOnline);
let memberCnt = notReceiveMembers.length;
console.log('##### SEND_START', memberCnt, notReceiveMembers)
let addItems: Map<string, { member: WoodenHorseMember, items: {id: number, count: number}[] }> = new Map();
for(let [id, {total, max}] of items) {
let randResult = getRandResultByMember(total, max, memberCnt);
for(let i = 0; i < memberCnt; i++) {
let member = notReceiveMembers[i];
let count = randResult.arr[i]||0;
if(count > 0) {
if(!addItems.has(member.roleId)) {
addItems.set(member.roleId, { member: member, items: [] });
}
addItems.get(member.roleId).items.push({ id, count });
}
}
woodenHorse.setRemainItem(id, randResult.remain, max);
}
for(let [_roleId, {member, items}] of addItems) {
member.setReceived(true);
this.handleItems(member.roleId, member.sid, items);
}
}
// 初始进入就随机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(!event.useDistance() && endTime) {
if(Date.now() > endTime) continue;
}
if(event.useDistance() && 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);
sendMessageToUserWithSuc(roleId, PUSH_ROUTE.RACE_ITEM_UPDATE, { items: sendItems }, sid);
return items;
}
public send(guildCode: string) {
this.hasSentGuild.push(guildCode);
}
public hasSend(guildCode: string) {
return this.hasSentGuild.indexOf(guildCode) != -1;
}
public async calServerHorses(serverId: number) {
let { guildRank: ranks } = await this.getRanks(serverId);
// 找到往前和往后2艘船
for (let i = 0; i < ranks.length; i++) {
await this.getScreenHorses(serverId, ranks, i, true);
}
}
private getScreenHorseRanks(ranks: RaceActivityRankParam[], i: number) {
let curRank = ranks[i];
if(!curRank || curRank.durability == 0) return;
let beforeHorses: RaceActivityRankParam[] = [], afterHorses: RaceActivityRankParam[] = [], beforeCnt = 0, afterCnt = 0;
for(let j = i - 1; j >= 0; j--) {
if(ranks[j]) {
beforeHorses.push(ranks[j]);
if(ranks[j].durability > 0) beforeCnt ++
}
if(beforeCnt >= 2) break;
}
for(let j = i + 1; j < ranks.length; j++) {
if(ranks[j]) {
afterHorses.push(ranks[j]);
if(ranks[j].durability > 0) afterCnt++;
}
if(afterCnt >= 2) break;
}
// 发送
// console.log('send', woodenHorseList.length);
return [...beforeHorses.reverse(), curRank, ...afterHorses]
}
private async getScreenHorses(serverId: number, ranks: RaceActivityRankParam[], i: number, needSend: boolean) {
let curRank = ranks[i];
if(!curRank) return;
// 发送
// console.log('send', woodenHorseList.length);
let wh = await this.getWoodenHorse(curRank.code, serverId);
let screenRank = this.getScreenHorseRanks(ranks, i);
let woodenHorseList: WoodenHorse[] = [];
if(curRank.durability != 0) {
for(let rank of screenRank) {
if(rank.code == curRank.code) {
woodenHorseList.push(wh);
} else {
let wh = await this.getWoodenHorse(rank.code, serverId);
woodenHorseList.push(wh);
}
}
}
if(needSend) {
let events = this.getEvents(curRank.code, wh ? wh.distance : 0);
await sendMessageToGuildWithSuc(curRank.code, PUSH_ROUTE.GUILD_RACE_UPDATE, { timestamp: Date.now(), woodenHorseList, guildRank: ranks, myGuildRank: curRank, events });
}
return woodenHorseList
}
}