diff --git a/game-server/app/servers/guild/handler/cityActivityHandler.ts b/game-server/app/servers/guild/handler/cityActivityHandler.ts index 140e36a0c..a5f30b73a 100644 --- a/game-server/app/servers/guild/handler/cityActivityHandler.ts +++ b/game-server/app/servers/guild/handler/cityActivityHandler.ts @@ -105,7 +105,7 @@ export class CityActivityHandler { const serverId = session.get('serverId'); const guildCode = session.get('guildCode'); - //TODO 权限校验 + //TODO 权限校验&时间校验 let { cityId } = msg; let checkResult = await GuildActivityCityModel.checkDeclartion(serverId, guildCode); diff --git a/game-server/app/servers/guild/handler/gateActivityHandler.ts b/game-server/app/servers/guild/handler/gateActivityHandler.ts index 3651049f0..5fbec98a4 100644 --- a/game-server/app/servers/guild/handler/gateActivityHandler.ts +++ b/game-server/app/servers/guild/handler/gateActivityHandler.ts @@ -1,5 +1,5 @@ import { Application, BackendSession, ChannelService, pinus } from "pinus"; -import { getMedianCe, getGuildActivityStatus, getRecordScore, getGateActivityObj, sendSingleGuildGateActEndMsg, sendGuildActEndMsg, participants, getGateActivityRank } from "../../../services/guildActivityService"; +import { getMedianCe, getGuildActivityStatus, getRecordScore, getGateActivityObj, sendSingleGateActEndMsg, sendGuildActEndMsg, participants, getGateActivityRank } from "../../../services/guildActivityService"; import { resResult } from "../../../pubUtils/util"; import { STATUS, GUILD_ACTIVITY_TYPE, GUILD_POINT_WAYS, ENEMIES_TYPE, GET_POINT_WAYS } from "../../../consts"; import { GameModel } from "../../../db/Game"; @@ -177,7 +177,7 @@ export class GateActivityHandler { gateHp = obj.getGateHpAndInc(guildCode, -1 * damage); if(gateHp <= 0) { // 推送 停止活动并结算奖励 - await sendSingleGuildGateActEndMsg(guildCode, serverId); + await sendSingleGateActEndMsg(guildCode, serverId); } // 推送 城门血量 let chatSid = await getGuildChannelSid(guildCode); @@ -322,4 +322,21 @@ export class GateActivityHandler { await sendGuildActEndMsg(aid); return resResult(STATUS.SUCCESS); } + + // ! 测试接口 将自己添加进活动roleId里 + async debugAddParticipants(msg: { aid: number }, session: BackendSession) { + let roleId = session.get('roleId'); + let guildCode = session.get('guildCode'); + if(!guildCode) return resResult(STATUS.GUILD_NOT_FOUND); + let serverId = session.get('serverId'); + let { aid } = msg; + await GuildActivityRecordModel.getRecord(guildCode, serverId, aid); + let userGuild = await UserGuildModel.getMyGuild(roleId); + let result = await GuildActivityRecordModel.updateInfo(guildCode, { memberCnt: 1, members: [{ roleId, job: userGuild.job }], auctionType: aid + 1 }); + + return resResult(STATUS.SUCCESS, { + sourceType: result.auctionType, + sourceCode: result.code + }); + } } diff --git a/game-server/app/services/guildActivityService.ts b/game-server/app/services/guildActivityService.ts index e43d50178..bfa2313c5 100644 --- a/game-server/app/services/guildActivityService.ts +++ b/game-server/app/services/guildActivityService.ts @@ -2,23 +2,22 @@ import { ServerlistModel } from "../db/Serverlist"; import { RoleModel } from "../db/Role"; import { reduceCe } from "../pubUtils/util"; import { GUILDACTIVITY } from "../pubUtils/dicParam"; -import { gameData, getGuildAuctionRewards } from "../pubUtils/data"; +import { gameData, getGuildAuctionRewards, getCityActivityRewards } from "../pubUtils/data"; import { getCurHourPoint, getCutDay, nowSeconds } from "../pubUtils/timeUtil"; import { GUILD_ACTIVITY_STATUS, GET_POINT_WAYS, GUILD_ACTIVITY_TYPE, REDIS_KEY, AUCTION_SOURCE, MAIL_TYPE, CITY_STATUS } from "../consts"; import { Record, UserGuildActivityRecModel } from "../db/UserGuildActivityRec"; -import { GateMembersRec, GateActivityObject, CityActivityObject, CityParam } from "../domain/battleField/guildActivity"; +import { GateMembersRec, GateActivityObject, CityActivityObject, CityParam, Member } from "../domain/battleField/guildActivity"; import { DicGuildActivity } from "../pubUtils/dictionary/DicGuildActivity"; import { getUnionRank, getRank, getGuildKeyName, getMyUnionRank, getRankScore, getCityKeyName } from "./redisService"; import { GuildModel } from "../db/Guild"; import { SimpleGuildRankParam, SimpleRoleRankParam } from "../domain/rank"; -import { getGuildChannelSid, getWorldChannelSid } from "./chatChannelService"; +import { getGuildChannelSid, getWorldChannelSid, getCityChannelSid } from "./chatChannelService"; import { pinus } from "pinus"; import { GuildActivityRecordModel } from "../db/GuildActivityRec"; -import { uniq } from 'underscore' import { genAuction } from "./auctionService"; import { sendMail } from "./mailService"; import { getHonourObject } from '../pubUtils/itemUtils'; -import { GuildActivityCityType } from "../db/GuildActivityCity"; +import { GuildActivityCityType, GuildActivityCityModel } from "../db/GuildActivityCity"; let gateActivityObj: GateActivityObject; let cityActivityObj: CityActivityObject; @@ -225,39 +224,65 @@ export async function sendAllGuildRanks(aid: number) { * @param aid 活动类型 */ export async function sendGuildActEndMsg(aid: number) { - let obj = getGateActivityObj(); - let guilds = obj.getGuilds(); - for(let [ serverId, guildCodes ] of guilds) { - let chatSid = await getWorldChannelSid(serverId); - pinus.app.rpc.chat.chatRemote.sendGuildActivityEnd.toServer(chatSid, serverId); - if(aid == GUILD_ACTIVITY_TYPE.GATE_ACTIVITY) { + if(aid == GUILD_ACTIVITY_TYPE.GATE_ACTIVITY) { + let obj = getGateActivityObj(); + let guilds = obj.getGuilds(); + for(let [ serverId, guildCodes ] of guilds) { + let chatSid = await getWorldChannelSid(serverId); + pinus.app.rpc.chat.chatRemote.sendGuildActivityEnd.toServer(chatSid, serverId); + for(let guildCode of guildCodes) { await gateActivitySettleReward(guildCode, serverId); } } + } else if (aid == GUILD_ACTIVITY_TYPE.CITY_ACTIVITY) { + let obj = getCityActivityObj(); + let { cities, serverlists} = obj.getAllCities(); + for(let { serverId, cityId } of cities) { + await cityActivitySettleReward(cityId, serverId); + } + // 发完之后再做下周自动宣战 + for(let serverId of serverlists) { + await autoDeclare(serverId); + } } } /** * 单个军团城门血条破了之后给他发奖励 - * @param guildCode + * @param guildCode 军团code */ -export async function sendSingleGuildGateActEndMsg(guildCode: string, serverId: number) { +export async function sendSingleGateActEndMsg(guildCode: string, serverId: number) { let chatSid = await getGuildChannelSid(guildCode); pinus.app.rpc.chat.guildRemote.sendGuildActivityEnd.toServer(chatSid, guildCode); await gateActivitySettleReward(guildCode, serverId); } + /** - * 军团结算奖励 - * @param guildCode - * @param serverId + * 单个城池城门血条破了之后给他发奖励 + * @param guildCode 军团code + */ +export async function sendSingleCityActEndMsg(cityId: number, serverId: number) { + let chatSid = await getCityChannelSid(cityId); + let obj = getCityActivityObj(); + let guildCodes = obj.getGuildsInCity(serverId, cityId); + for(let guildCode of guildCodes) { + pinus.app.rpc.chat.guildRemote.sendGuildActivityEnd.toServer(chatSid, guildCode); + } + await cityActivitySettleReward(cityId, serverId); +} + + +/** + * 结算蛮夷入侵奖励 + * @param guildCode 军团code + * @param serverId 服务器id */ export async function gateActivitySettleReward(guildCode: string, serverId: number) { let obj = getGateActivityObj(); let { gateHp, members } = obj.getObj(guildCode, serverId); - members = uniq(members, cur => cur.roleId); let rank = await getMyUnionRank(REDIS_KEY.GATE_ACTIVITY, serverId, guildCode); let guildScore = await getRankScore(REDIS_KEY.GATE_ACTIVITY, serverId, guildCode); @@ -277,10 +302,10 @@ export async function gateActivitySettleReward(guildCode: string, serverId: numb let memberRankResult = await getRank(getGuildKeyName(REDIS_KEY.USER_GATE_ACTIVITY, guildCode), serverId, ''); for(let { rank, roleId, num: myScore } of memberRankResult.ranks) { let honour = dic.honour + myScore * GUILDACTIVITY.GATEACTIVITY_HONOUR_RATIO; - let honourObj = getHonourObject(Math.floor(honour)); - await sendMail(MAIL_TYPE.GUILD_ACTIVITY_REWARD, roleId, '系统', [], [honourObj]) - - await UserGuildActivityRecModel.updateInfoByRoleId(roleId, { score: myScore, rank }); + await updateUserRecAndSendHonour(honour, myScore, rank, roleId, members); + } + for(let { roleId } of members) { // 只参加了,没有分数的人 + await updateUserRecAndSendHonour(dic.honour, 0, 0, roleId, members); } // 加入拍卖行 @@ -289,6 +314,80 @@ export async function gateActivitySettleReward(guildCode: string, serverId: numb obj.delGuildRecord(guildCode, serverId); } +async function updateUserRecAndSendHonour(honour: number, myScore: number, rank: number, roleId: string, members: Member[]) { + let honourObj = getHonourObject(Math.floor(honour)); + await sendMail(MAIL_TYPE.GUILD_ACTIVITY_REWARD, roleId, '系统', [], [honourObj]) + + await UserGuildActivityRecModel.updateInfoByRoleId(roleId, { score: myScore, rank }); + let index = members.findIndex(cur => cur.roleId == roleId); + members.splice(index, 1); +} + + +/** + * 结算诸侯入侵奖励 + * @param cityId 城镇id + * @param serverId 服务器id + */ +export async function cityActivitySettleReward(cityId: number, serverId: number) { + let obj = getCityActivityObj(); + + let dicCity = gameData.cityActivity.get(cityId); + if(!dicCity) return; + let gateHp = obj.getGateHpAndInc(serverId, cityId, dicCity.hp); + let isSuccess = gateHp <= 0; // 血条未击破则没有占领军团 + + let guildRankRsult = await getUnionRank(getCityKeyName(REDIS_KEY.CITY_ACTIVITY, cityId), serverId, ''); + for(let { rank: guildRank, code: guildCode, name, num } of guildRankRsult.ranks) { + if(guildRank == 1) { + if(isSuccess) { + await GuildActivityCityModel.guard(serverId, cityId, guildCode, name); // 占领 + } else { + await GuildActivityCityModel.guard(serverId, cityId, "", ""); // 无人能占领 + } + } + let rewards = getGuildAuctionRewards(GUILD_ACTIVITY_TYPE.CITY_ACTIVITY, guildRank); + let members = obj.getMembersOfGuild(guildCode); + + let rec = await GuildActivityRecordModel.updateInfo(guildCode, { + memberCnt: members.length, members, + isSuccess, isCompleted: true, + rank: guildRank, damage: num, remainGateHp: gateHp, + rewards, + auctionType: AUCTION_SOURCE.CITY, + }); + + // 奖励加入拍卖行 + await genAuction(guildCode, AUCTION_SOURCE.GATE, rec.code, serverId, rewards); + + let dic = gameData.guildActivity.get(GUILD_ACTIVITY_TYPE.CITY_ACTIVITY); + let memberRankResult = await getRank(getGuildKeyName(REDIS_KEY.USER_GATE_ACTIVITY, guildCode), serverId, ''); + let userRank = 0; + for(let { rank, roleId, num: myScore } of memberRankResult.ranks) { + let honour = dic.honour + getCityActivityRewards(dicCity.type, guildRank, rank); + await updateUserRecAndSendHonour(honour, myScore, rank, roleId, members); + userRank = rank; + } + for(let { roleId } of members) { // 只参加了,没有分数的人 + let honour = dic.honour + getCityActivityRewards(dicCity.type, guildRank, userRank); + await updateUserRecAndSendHonour(honour, 0, 0, roleId, members); + } + } +} + +/** + * 清空完declareGuilds之后,做下一次活动的自动宣战 + */ +async function autoDeclare(serverId: number) { + let allCities = await GuildActivityCityModel.getAllCities(serverId); + for(let { cityId, guardGuildCode } of allCities) { + let dicCity = gameData.cityActivity.get(cityId); + if(guardGuildCode && dicCity.nextCity) { + await GuildActivityCityModel.declare(serverId, dicCity.nextCity, guardGuildCode); + } + } +} + /** * 获取活动参加者 * @param guildCode 军团code @@ -302,6 +401,11 @@ export async function participants(guildCode: string, sourceType: number, source return rec.members||[]; } +/** + * 获取诸侯入侵各个城池状态 + * @param guildCode 我方军团 + * @param dbCities 所有城池 + */ export function getCities(guildCode: string, dbCities: GuildActivityCityType[]) { let cities = new Array(); diff --git a/shared/consts/constModules/sysConst.ts b/shared/consts/constModules/sysConst.ts index 9ac080bc1..a026d1db9 100644 --- a/shared/consts/constModules/sysConst.ts +++ b/shared/consts/constModules/sysConst.ts @@ -351,6 +351,7 @@ export const FILENAME = { DIC_CITY_ACTIVITY: 'dic_zyz_cityActivity', DIC_CHAT_ACCUSE: 'dic_zyz_chat_report', DIC_CHAT_SYSTEM: 'dic_zyz_chat_system', + DIC_CITY_ACTIVITY_REWARD: 'dic_zyz_cityActivityReward' } export const WAR_RELATE_TABLES = [ diff --git a/shared/db/GuildActivityCity.ts b/shared/db/GuildActivityCity.ts index db825abde..ac632c72d 100644 --- a/shared/db/GuildActivityCity.ts +++ b/shared/db/GuildActivityCity.ts @@ -1,6 +1,6 @@ import BaseModel from './BaseModel'; import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; -import { getTodayZeroDate } from '../pubUtils/timeUtil'; +import { getCurWeekDate} from '../pubUtils/timeUtil'; @index({ serverId: 1, cityId: 1, createdAt: 1 }) export default class GuildActivityCity extends BaseModel { @@ -23,34 +23,47 @@ export default class GuildActivityCity extends BaseModel { @prop({ required: true }) guardGuildName: string; // 占领的军团名 + @prop({ required: true }) + guardTime: Date; // 占领日期 // 每天宣战一次 public static async getAllCities(serverId: number) { - let today = getTodayZeroDate(); - let rec: GuildActivityCityType[] = await GuildActivityCityModel.find({ serverId, createdAt: { $gte: today }}).lean(); - + let curWeek = getCurWeekDate(1, 0); + let rec: GuildActivityCityType[] = await GuildActivityCityModel.find({ serverId, createdAt: { $gte: curWeek }}).lean(); + return rec; } // 检查是否宣战过 public static async checkDeclartion(serverId: number, guildCode: string) { - let today = getTodayZeroDate(); + let curWeek = getCurWeekDate(1, 0); let rec: GuildActivityCityType = await GuildActivityCityModel.findOne( - { serverId, createdAt: { $gte: today }, declareGuilds: { $in: [guildCode]}}).lean(); + { serverId, createdAt: { $gte: curWeek }, declareGuilds: { $in: [guildCode]}}).lean(); return rec; } - // 每天宣战一次 + // 宣言 public static async declare(serverId: number, cityId: number, guildCode: string) { - let today = getTodayZeroDate(); + let curWeek = getCurWeekDate(1, 0); let rec: GuildActivityCityType = await GuildActivityCityModel.findOneAndUpdate( - { serverId, cityId, createdAt: { $gte: today } }, - { $setOnInsert: { cityId }, $push: { declareGuilds: guildCode }, $inc: {declareCount: 1 } }, + { serverId, cityId, createdAt: { $gte: curWeek } }, + { $setOnInsert: { serverId, cityId }, $push: { declareGuilds: guildCode }, $inc: {declareCount: 1 } }, {new: true, upsert: true}).lean(); return rec; } + + // 占领 + public static async guard(serverId: number, cityId: number, guildCode: string, guildName: string) { + let curWeek = getCurWeekDate(1, 0); + let rec: GuildActivityCityType = await GuildActivityCityModel.findOneAndUpdate( + { serverId, cityId, createdAt: { $gte: curWeek } }, + { $set: { declareCount: 0, declareGuilds: [], guardGuildCode: guildCode, guardGuildName: guildName, guardTime: new Date()} }, + { new: true }).lean(); + + return rec; + } } export const GuildActivityCityModel = getModelForClass(GuildActivityCity); diff --git a/shared/db/GuildActivityRec.ts b/shared/db/GuildActivityRec.ts index 2c2498965..4672948da 100644 --- a/shared/db/GuildActivityRec.ts +++ b/shared/db/GuildActivityRec.ts @@ -1,5 +1,5 @@ import BaseModel from './BaseModel'; -import { index, getModelForClass, prop, DocumentType, Ref } from '@typegoose/typegoose'; +import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; import { ItemReward } from '../domain/dbGeneral'; import { getTodayZeroDate } from '../pubUtils/timeUtil'; import { genCode } from '../pubUtils/util'; diff --git a/shared/db/Serverlist.ts b/shared/db/Serverlist.ts index 175936997..555151446 100644 --- a/shared/db/Serverlist.ts +++ b/shared/db/Serverlist.ts @@ -1,4 +1,3 @@ -import { APP_ID } from './../consts'; import BaseModel from './BaseModel'; import { index, getModelForClass, prop, DocumentType, modelOptions } from '@typegoose/typegoose'; diff --git a/shared/db/UserGuildActivityRec.ts b/shared/db/UserGuildActivityRec.ts index 10907f647..91ca79033 100644 --- a/shared/db/UserGuildActivityRec.ts +++ b/shared/db/UserGuildActivityRec.ts @@ -1,5 +1,5 @@ import BaseModel from './BaseModel'; -import { index, getModelForClass, prop, DocumentType, Ref } from '@typegoose/typegoose'; +import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; import { getTodayZeroDate } from '../pubUtils/timeUtil'; import { genCode } from '../pubUtils/util'; diff --git a/shared/domain/battleField/guildActivity.ts b/shared/domain/battleField/guildActivity.ts index bd92ab234..4297e6ac5 100644 --- a/shared/domain/battleField/guildActivity.ts +++ b/shared/domain/battleField/guildActivity.ts @@ -50,7 +50,10 @@ export class GateActivityObject { public pushMembers(guildCode: string, serverId: number, roleId: string, job: number) { if(this.members.has(guildCode)) { - this.members.get(guildCode).push({ roleId, job }); + let members = this.members.get(guildCode); + if(members.findIndex(cur => cur.roleId == roleId) == -1) { + members.push({ roleId, job }); + } } else { let arr = new Array(); arr.push(roleId); @@ -101,6 +104,14 @@ export class CityActivityObject { 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 { @@ -111,6 +122,27 @@ export class CityActivityObject { } } + public getAllCities() { + + let allCities = new Array<{ serverId: number, cityId: number, guildCodes: string[]}>(); + let serverlists = new Array(); + 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); @@ -137,7 +169,10 @@ export class CityActivityObject { public pushMembers(guildCode: string, roleId: string, job: number) { if(this.members.has(guildCode)) { - this.members.get(guildCode).push({ roleId, job }); + let members = this.members.get(guildCode); + if(members.findIndex(cur => cur.roleId == roleId) == -1) { + members.push({ roleId, job }); + } } else { let arr = new Array(); arr.push(roleId); diff --git a/shared/pubUtils/data.ts b/shared/pubUtils/data.ts index 2db9ae1db..bd78d2c1d 100644 --- a/shared/pubUtils/data.ts +++ b/shared/pubUtils/data.ts @@ -64,6 +64,7 @@ import { dicGuildAuction } from './dictionary/DicGuildAuction'; import { getCutDay } from "./timeUtil"; import { dicCityActivity } from "./dictionary/DicCityActivity"; import { dicChatAccuse } from "./dictionary/DicChatAccuse"; +import { dicCityActivityReward } from "./dictionary/DicCityActivityReward"; export const gameData = { blurprtCompose: dicBlueprtCompose, @@ -151,6 +152,7 @@ export const gameData = { guildAuction: dicGuildAuction, cityActivity: dicCityActivity, chatAccuse: dicChatAccuse, + cityActivityReward: dicCityActivityReward }; // 在此提供一些原先在gamedata中提供的方法,以便更方便获取gameData数据 @@ -474,4 +476,18 @@ export function getGuildAuctionRewards(aid: number, rank: number) { return rank >= cur.min && (rank <= cur.max || cur.max == 0); }); return dic?dic.rewards: new Array(); +} + +/** + * 根据军团活动排名获得功勋奖励 + * @param type 城池类型 + * @param guildRank 军团排名 + * @param rank 成员在军团内部排名 + */ +export function getCityActivityRewards(type: number, guildRank: number, rank: number) { + let ranksReward = gameData.cityActivityReward.get(type)||[]; + let dic = ranksReward.find(cur => { + return cur.guildRank == guildRank && (rank >= cur.min && (rank <= cur.max || cur.max == 0)); + }); + return dic?dic.honour: 0; } \ No newline at end of file diff --git a/shared/pubUtils/dictionary/DicCityActivityReward.ts b/shared/pubUtils/dictionary/DicCityActivityReward.ts new file mode 100644 index 000000000..eaecd535e --- /dev/null +++ b/shared/pubUtils/dictionary/DicCityActivityReward.ts @@ -0,0 +1,33 @@ +// 诸侯混战军团排名奖励表 +import { readJsonFile } from '../util' +import { FILENAME } from '../../consts' + +export interface DicCityActivityReward { + + // 城池id + readonly id: number; + // 城池类型 + readonly type: number; + // 军团排名 + readonly guildRank: number; + // 军团内排名最小值 + readonly min: number; + // 军团内排名最大值 + readonly max: number; + // 可获得功勋 + readonly honour: number; +} + +const str = readJsonFile(FILENAME.DIC_CITY_ACTIVITY_REWARD); +let arr = JSON.parse(str); + +export const dicCityActivityReward = new Map(); + +arr.forEach(o => { + if(dicCityActivityReward.has(o.type)) { + dicCityActivityReward.get(o.type).push(o); + } else { + dicCityActivityReward.set(o.type, [o]); + } +}); +arr = undefined; \ No newline at end of file