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

561 lines
23 KiB
TypeScript

// 军团活动蛮夷入侵城门血量等数据存储
import { WoodenHorse, Event, WoodenHorseMember, RaceActivityRankParam, RaceActivityData, MemberInfo, GuildInfo } from "../../domain/battleField/guildActivity";
import { getRaceEventItems, gameData } from "../../pubUtils/data";
import { GuildModel } from "../../db/Guild";
import { sendSingleRaceActEndMsg } from "./guildActivityService";
import { RACE_EVENT_TYPE, RACE_EVENT_EFFECT_TYPE, RACE_EVENT, PUSH_ROUTE, GUILD_ACTIVITY_STATUS, RACE_ACTIVITY_STATUS } from "../../consts";
import { getRandEelm, sortArrRandom, getRandResultByMember } from "../../pubUtils/util";
import { sendMessageToGuildWithSuc, sendMessageToUserWithSuc } from "../pushService";
import { GUILDACTIVITY } from "../../pubUtils/dicParam";
// 粮草先行
export class RaceActivityObject {
data: RaceActivityData = new RaceActivityData();
public getStatus() {
return this.data.status;
}
public getItem(roleId: string) {
return this.data.items.get(roleId)||[]
}
// 是否加入过
public getMember(guildCode: string, roleId: string) {
let member = this.data.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);
let index = wh.members.findIndex(cur => cur.roleId == roleId);
if(index != -1) {
wh.members[index].updateSid(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);
this.leaveMemberSid(wh, 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);
this.leaveMemberSid(wh, roleId, true);
}
public dismiss(guildCode: string) {
let guild = this.data.guildList.find(guild => guild.guildCode == guildCode);
if(!guild) return;
guild.dismiss();
this.data.woodenHorses.delete(guildCode);
}
// 加入member
private pushMember(guildCode: string, roleId: string, job: number, code: string) {
if(!this.data.members.has(guildCode)) {
this.data.members.set(guildCode, []);
}
this.data.members.get(guildCode).push(new MemberInfo(roleId, job, code));
}
public getGuilds() {
return this.data.guildList.filter(cur => !cur.isDissmiss);
}
public getMembersOfGuild(guildCode: string) {
let members = this.data.members.get(guildCode)||[];
return members.filter(cur => !cur.isQuit);
}
public getAllWoodenHorses() {
return this.data.woodenHorses;
}
public async getRanks(serverId: number, guildCode?: string) {
let myRank: RaceActivityRankParam = null;
let ranks: RaceActivityRankParam[] = [];
let myIndex = -1;
for(let [_, _wh] of this.data.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;
this.joinMember(woodenHorse, roleId, roleName, sid, code)
this.pushMember(guildCode, roleId, job, code);
if(this.data.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.data.woodenHorses.has(guildCode)) {
this.initEvents(guildCode);
if(isDebug) {
this.data.woodenHorses.set(guildCode, new WoodenHorse(guildCode, guildCode, 0, serverId, this.data.allStartTime, false));
this.data.guildList.push(new GuildInfo(serverId, guildCode));
} else {
let guild = await GuildModel.findByCode(guildCode, serverId);
if(!guild) return undefined;
let { name: guildName, guildCe } = guild;
this.data.woodenHorses.set(guildCode, new WoodenHorse(guildCode, guildName, guildCe, serverId, this.data.allStartTime, false));
this.data.guildList.push(new GuildInfo(serverId, guildCode));
}
}
let woodenHorse = this.data.woodenHorses.get(guildCode);
let events = this.data.events.get(guildCode)||[];
let needSendEnd = this.calCurWoodenHorse(woodenHorse, 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.data.events.has(toGuild)) {
this.data.events.set(toGuild, [event]);
} else {
let events = this.data.events.get(toGuild)||[];
events.push(event);
this.data.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.data.status = GUILD_ACTIVITY_STATUS.START;
if(this.data.allStartTime == 0) this.data.allStartTime = Date.now();
let guildCodes = new Array<string>();
for(let [code, woodenHorse] of this.data.woodenHorses) {
if(woodenHorse.memberCnt > 0) {
this.woodenHorseStartRace(woodenHorse);
guildCodes.push(code);
}
}
return guildCodes;
}
public stopRace() {
this.data.status = GUILD_ACTIVITY_STATUS.END;
for(let [_, woodenHorse] of this.data.woodenHorses) {
woodenHorse.status = RACE_ACTIVITY_STATUS.END;
}
}
private woodenHorseStartRace(woodenHorse: WoodenHorse) {
woodenHorse.status = RACE_ACTIVITY_STATUS.START;
woodenHorse.time = Date.now();
woodenHorse.startTime = Date.now();
woodenHorse.allStartTime = this.data.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 });
}
}
this.setRemainItem(woodenHorse, 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.data.events.get(guildCode)) {
this.data.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.data.events.get(guildCode).push(event);
} else if (type == RACE_EVENT_TYPE.EVENT) {
let event = new Event(events[index], guildCode, guildCode, 1, distance);
this.data.events.get(guildCode).push(event);
index ++;
}
}
}
public getEvents(guildCode: string, distance: number) {
let events = this.data.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.data.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.data.items.set(roleId, items);
sendMessageToUserWithSuc(roleId, PUSH_ROUTE.RACE_ITEM_UPDATE, { items: sendItems }, sid);
return items;
}
public send(guildCode: string) {
this.data.hasSentGuild.push(guildCode);
}
public hasSend(guildCode: string) {
return this.data.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
}
/**
* 根据时间计算当前木马速度距离耐久等
* @param events
* @returns {boolean} needSendEnd 是否跑到终点发送结束新号
*/
public calCurWoodenHorse(woodenHorse: WoodenHorse, events: Event[]): boolean {
if(woodenHorse.status == RACE_ACTIVITY_STATUS.END) return false;
if(woodenHorse.status == RACE_ACTIVITY_STATUS.START) {
if(woodenHorse.distance >= GUILDACTIVITY.RACEACTIVITY_LENGTH) {
woodenHorse.distance = GUILDACTIVITY.RACEACTIVITY_LENGTH;
woodenHorse.status = RACE_ACTIVITY_STATUS.END;
woodenHorse.speed = 0;
return true;
}
woodenHorse.distance = Math.floor((woodenHorse.distance + (Date.now() - woodenHorse.time)/1000 * woodenHorse.speed ) * 1000)/1000; // 1位小数点
woodenHorse.time = Date.now();
}
let effectiveEvents = new Array<Event>();
for(let i = 0; i < events.length; i++) {
let event = events[i];
if(event.useDistance() && event.startDistance && woodenHorse.distance > event.startDistance) {
let startTime = Date.now() - Math.floor((woodenHorse.distance - event.startDistance) / woodenHorse.speed);
event.setStartTime(startTime); // 距离生效的事件的实际生效时间,主要用于速度叠加顺序
}
let isEffective = false;
if(event.useTime()) {
if(event.startTime <= Date.now() && event.endTime > Date.now()) {
isEffective = true;
}
if(event.endTime < Date.now()) {
if(event.endTime && event.startTime == event.endTime) {
isEffective = true;
}
let index = events.findIndex(cur => cur.id == event.id);
events.splice(index, 1);
}
}
if(event.useDistance()) {
if(event.startDistance <= woodenHorse.distance && event.endDistance > woodenHorse.distance) {
isEffective = true;
}
if(event.endDistance < woodenHorse.distance) {
if(event.endDistance && event.startDistance == event.endDistance) {
isEffective = true;
}
let index = events.findIndex(cur => cur.id == event.id);
events.splice(index, 1);
}
}
if(isEffective) {
effectiveEvents.push(event);
}
}
effectiveEvents.sort((a, b) => a.startTime - b.startTime);
woodenHorse.speed = GUILDACTIVITY.RACE_INIT_SPEED + woodenHorse.memberCnt * GUILDACTIVITY.RACE_PER_SPEED;
for(let { id, count, endTime } of effectiveEvents) {
this.calEvent(woodenHorse, id, count, endTime);
}
if(woodenHorse.durability <= 0) {
woodenHorse.status = RACE_ACTIVITY_STATUS.BREAK;
woodenHorse.speed = 0;
}
return false;
}
private calEvent(woodenHorse: WoodenHorse, id: number, count: number = 1, endTime?: number) {
let { effect } = gameData.raceActivityEvents.get(id);
switch (id) {
case RACE_EVENT.LIANNU:
if (woodenHorse.shieldTime < Date.now()) {
if (woodenHorse.shield >= count) {
woodenHorse.shield -= count;
} else {
woodenHorse.shield = 0;
woodenHorse.durability -= (count - woodenHorse.shield) * effect[0];
if(woodenHorse.durability > 100) woodenHorse.durability = 100;
if(woodenHorse.durability < 0) woodenHorse.durability = 0;
}
}
break;
case RACE_EVENT.GUISHOUYINFU:
if (woodenHorse.shieldTime < Date.now()) {
woodenHorse.time = endTime;
woodenHorse.speed = effect[1]||0.1;
}
break;
case RACE_EVENT.FENGCHE:
case RACE_EVENT.WUGUIBANYUNFU:
woodenHorse.speed *= Math.pow(1 + effect[0] / 100, count); break;
case RACE_EVENT.LUDUN:
woodenHorse.shield += count * effect[0]; break;
case RACE_EVENT.TIANSHIDUNFU:
woodenHorse.shieldTime = endTime; break;
case RACE_EVENT.JIASU_1:
woodenHorse.speed *= Math.pow(1 + effect[0] / 100, count); break;
case RACE_EVENT.JIASU_2:
woodenHorse.speed += effect[0]; break;
case RACE_EVENT.HUIFU_1:
woodenHorse.durability += effect[0];
if(woodenHorse.durability > 100) woodenHorse.durability = 100;
if(woodenHorse.durability < 0) woodenHorse.durability = 0;
break;
case RACE_EVENT.JIANSU_1:
woodenHorse.speed *= Math.pow(1 - effect[0] / 100, count); break;
case RACE_EVENT.JIANSU_2:
woodenHorse.speed -= effect[0];
if(woodenHorse.speed < 0) woodenHorse.speed = 0;
break;
case RACE_EVENT.SHANGHAI_1:
woodenHorse.durability -= effect[0];
if(woodenHorse.durability > 100) woodenHorse.durability = 100;
if(woodenHorse.durability < 0) woodenHorse.durability = 0;
break;
case RACE_EVENT.ITEM:
let onlineMembers = woodenHorse.members.filter(member => member.isOnline);
let memberCnt = onlineMembers.length;
console.log('##### HANDLE_ITEM', memberCnt, onlineMembers)
let ranMember: WoodenHorseMember[] = getRandEelm(onlineMembers, GUILDACTIVITY.RACEACTIVITY_EVENT_MEMBERCNT);
if(ranMember.length <= 0) ranMember = onlineMembers;
for(let member of ranMember) {
let item = gameData.raceEventItems;
member.addTempItems(item);
}
let normalItems = getRaceEventItems();
for(let [id, {total, max}] of normalItems) {
let randResult = getRandResultByMember(total, max, memberCnt);
for(let i = 0; i < onlineMembers.length; i++) {
let count = randResult.arr[i]||0;
if(count > 0) {
onlineMembers[i].addTempItem({ id, count });
normalItems.get(id).total -= count;
}
}
}
break;
}
}
public joinMember(woodenHorse: WoodenHorse, roleId: string, roleName: string, sid: string, code: string) {
let index = woodenHorse.members.findIndex(cur => cur.roleId == roleId)
if(index == -1) {
let member = new WoodenHorseMember(roleId, roleName, sid, code);
woodenHorse.members.push(member);
woodenHorse.speed++;
woodenHorse.memberCnt++;
return member;
} else {
return woodenHorse.members[index];
}
}
public leaveMemberSid(woodenHorse: WoodenHorse, roleId: string, isQuit = false) {
let index = woodenHorse.members.findIndex(cur => cur.roleId == roleId);
if(index != -1) {
woodenHorse.members[index].leave();
}
if(isQuit) woodenHorse.memberCnt--;
if(woodenHorse.memberCnt < 0) woodenHorse.memberCnt = 0;
}
public setRemainItem(woodenHorse: WoodenHorse, id: number, remain: number, max: number) {
woodenHorse.remainItems.set(id, { total: remain, max });
}
}