创建公会

This commit is contained in:
luying
2021-01-18 21:05:25 +08:00
parent 97216647b2
commit 3c35852495
17 changed files with 281 additions and 37 deletions

View File

@@ -1,12 +1,13 @@
import { Application, BackendSession } from 'pinus';
import { DailyRecordModel } from '../../../db/DailyRecord';
import { getGamedata } from '../../../pubUtils/gamedata';
import { GOLD_COST_RATIO, CURRENCY_BY_TYPE, CURRENCY_TYPE } from '../../../consts';
import { GOLD_COST_RATIO } from '../../../consts';
import { STATUS } from '../../../consts/statusCode';
import { resResult, calculateNum } from '../../../pubUtils/util';
import { RoleModel } from '../../../db/Role';
import { getDailyNum } from '../../../services/dailyBattleService';
import { handleCost } from '../../../services/rewardService';
import { getGoldObject } from '../../../pubUtils/itemUtils';
export default function(app: Application) {
return new DailyBattleHandler(app);
@@ -91,7 +92,7 @@ export class DailyBattleHandler {
return resResult(STATUS.DAILY_REFRESH_GOLD_LACK);
}
await handleCost(roleId, sid, [{id: CURRENCY_BY_TYPE.get(CURRENCY_TYPE.GOLD), count: buyCost}]);
await handleCost(roleId, sid, [getGoldObject(buyCost)]);
let newDailyRecord = await DailyRecordModel.increseBuyCount(roleId, type, count);
let checkDailyResult = await getDailyNum(newDailyRecord, timesPerDay, timesCanBuy);

View File

@@ -1,9 +1,10 @@
import { Application, BackendSession } from 'pinus';
import { GOLD_COST_RATIO, DUNGEON_CONST, CURRENCY_TYPE, CURRENCY_BY_TYPE } from '../../../consts';
import { GOLD_COST_RATIO, DUNGEON_CONST } from '../../../consts';
import { STATUS } from '../../../consts/statusCode';
import { resResult, calculateNum, shouldRefresh } from '../../../pubUtils/util';
import { RoleModel } from '../../../db/Role';
import { handleCost } from '../../../services/rewardService';
import { getGoldObject } from '../../../pubUtils/itemUtils';
export default function(app: Application) {
return new DungeonBattleHandler(app);
@@ -62,7 +63,7 @@ export class DungeonBattleHandler {
if(buyCost > gold) {
return resResult(STATUS.DAILY_REFRESH_GOLD_LACK);
}
await handleCost(roleId, sid, [{id: CURRENCY_BY_TYPE.get(CURRENCY_TYPE.GOLD), count: buyCost}]);
await handleCost(roleId, sid, [getGoldObject(buyCost)]);
await RoleModel.buyCnt(roleId, needRefresh, count, curTime);
let nextCostGold = calculateNum(GOLD_COST_RATIO.DUNGRON_BUY_NUM, {num: dungeonBuyCnt + count + 1 }, 50);

View File

@@ -1,8 +1,15 @@
import {Application, BackendSession, pinus} from 'pinus';
import { Application, BackendSession, pinus } from 'pinus';
import { resResult } from '../../../pubUtils/util';
import { STATUS } from '../../../consts';
import { STATUS, GUILD_OPERATE, GUILD_AUTH, GUILD_JOB } from '../../../consts';
import { UserGuildModel } from '../../../db/UserGuild';
import { checkAuth } from '../../../services/guildService';
import { GuildModel } from '../../../db/Guild';
import { RoleModel } from '../../../db/Role';
import { GUILD } from '../../../pubUtils/dicParam';
import { handleCost } from '../../../services/rewardService';
import { getGoldObject } from '../../../pubUtils/itemUtils';
export default function(app: Application) {
export default function (app: Application) {
return new GuildHandler(app);
}
@@ -11,13 +18,46 @@ export class GuildHandler {
}
//TODO创建军团
async createGuild() {
async createGuild(msg: { name: string, icon: number, notice: string }, session: BackendSession) {
const roleId = session.get('roleId');
const sid = session.get('sid');
const { name, icon, notice } = msg;
// 检查权限是否够,包括是否参过团
const { auth } = await UserGuildModel.getMyGuild(roleId);
const checkResult = checkAuth(GUILD_OPERATE.CREATE_GUILD, auth);
if(!checkResult) return resResult(STATUS.GUILD_AUTH_NOT_ENOUGH);
// 检查名字是否重
const checkNameResult = await GuildModel.checkName(name);
if(checkNameResult) return resResult(STATUS.GUILD_NAME_DUP);
// 检查元宝是否够
const role = await RoleModel.findByRoleId(roleId);
if(GUILD.GUILD_CREATE_COST > role.gold) { // TODO 系统参数表字段更改
return resResult(STATUS.DAILY_REFRESH_GOLD_LACK);
}
await handleCost(roleId, sid, [getGoldObject(GUILD.GUILD_CREATE_COST)]);
// 创建公会
const guild = await GuildModel.createGuild({ name, icon, notice, leader: role._id, members: [roleId], ce: role.ce });
if(!guild) return resResult(STATUS.GUILD_CREATE_ERROR);
const userGuild = await UserGuildModel.createUserGuild({ guildCode: guild.code, roleId, role: role._id, guild: guild._id, auth: GUILD_AUTH.LEADER, job: GUILD_JOB.JIANGJUN });
if(!userGuild) return resResult(STATUS.GUILD_CREATE_ERROR);
// TODO 加入排行
const rank = 0;
// 返回
const result = { ...guild, rank, myInfo: {...userGuild}};
return resResult(STATUS.SUCCESS, result);
}
//TODO 获取军团列表
async getGuildList(msg: {page: number, showPeopleMax: boolean, name: string }, session: BackendSession) {
async getGuildList(msg: { page: number, showPeopleMax: boolean, name: string }, session: BackendSession) {
const list = [{
code: "code",
name: "name",

View File

@@ -1,5 +1,5 @@
import { STATUS } from './../../../consts/statusCode';
import { HANG_UP_CONSTS, GOLD_COST_RATIO, TOWER_TASK_CONST, REDIS_KEY, CURRENCY_BY_TYPE, CURRENCY_TYPE } from './../../../consts';
import { HANG_UP_CONSTS, GOLD_COST_RATIO, TOWER_TASK_CONST, REDIS_KEY } from './../../../consts';
import { TowerTaskRecModel } from './../../../db/TowerTaskRec';
import { HangUpSpdUpRecModel } from './../../../db/HangUpSpdUpRec';
import { HangUpRecordModel } from './../../../db/HangUpRecord';
@@ -13,6 +13,7 @@ import { handleFixedReward, addItems, handleCost } from '../../../services/rewar
import { checkBattleHeroes } from '../../../services/normalBattleService';
import { getRank, setRank, initRank, existsRank } from '../../../services/redisService';
import { RankParam } from '../../../pubUtils/interface';
import { getGoldObject } from '../../../pubUtils/itemUtils';
export default function(app: Application) {
return new TowerBattleHandler(app);
@@ -135,7 +136,7 @@ export class TowerBattleHandler {
return resResult(STATUS.TOWER_GOLD_NOT_ENOUGH);
}
await handleCost(roleId, sid, [{id: CURRENCY_BY_TYPE.get(CURRENCY_TYPE.GOLD), count: costGold}])
await handleCost(roleId, sid, [getGoldObject(costGold)])
const spdUpResult = await RoleModel.hangUpSpdUp(roleId, msg.speedUpCnt, curTime);
if (!spdUpResult) {

View File

@@ -0,0 +1,12 @@
import { gameData } from "../pubUtils/data";
/**
* @description 检查该玩家是否有权限做操作
* @param func 操作id
* @param auth 权限
*/
export function checkAuth(func: number, auth: number) {
const dicGuildAuth = gameData.guildAuth.get(func);
if(!dicGuildAuth) return false;
return dicGuildAuth.includes(auth);
}

View File

@@ -56,6 +56,51 @@ describe('军团测试', function() {
done();
});
it('创建军团', function (done) {
pinusClient.request('battle.guildHandler.createGuild', { name: "test", icon: 1, notice: "notice" }, (res) => {
console.log(JSON.stringify(res))
// 消息回调
expect(res).to.be.an('object');
expect(res.code).equal(0);
expect(res.data).to.be.an('object');
expect(res.data).to.have.deep.property('code').that.is.an('string');
expect(res.data).to.have.deep.property('name').that.is.an('string');
expect(res.data).to.have.deep.property('icon').that.is.an('number');
expect(res.data).to.have.deep.property('notice').that.is.an('string');
expect(res.data).to.have.deep.property('introduce').that.is.an('string');
expect(res.data).to.have.deep.property('rank').that.is.an('number');
expect(res.data).to.have.deep.property('lv').that.is.an('number');
expect(res.data).to.have.deep.property('fund').that.is.an('number');
expect(res.data).to.have.deep.property('peopleNum').that.is.an('number');
expect(res.data).to.have.deep.property('manageNum').that.is.an('number');
expect(res.data).to.have.deep.property('activeDaily').that.is.an('number');
expect(res.data).to.have.deep.property('activeWeekly').that.is.an('number');
expect(res.data).to.have.deep.property('ceCondition').that.is.an('number');
expect(res.data).to.have.deep.property('isAuto').that.is.an('boolean');
expect(res.data).to.have.deep.property('leader').that.is.an('object');
expect(res.data.leader).to.have.deep.property('name').that.is.an('string');
expect(res.data.leader).to.have.deep.property('sHid').that.is.an('number');
expect(res.data.leader).to.have.deep.property('headHid').that.is.an('number');
expect(res.data.leader).to.have.deep.property('lv').that.is.an('number');
expect(res.data.leader).to.have.deep.property('loginTime').that.is.an('number');
expect(res.data).to.have.deep.property('myInfo').that.is.an('object');
expect(res.data.myInfo).to.have.deep.property('honour').that.is.an('number');
expect(res.data.myInfo).to.have.deep.property('active').that.is.an('number');
expect(res.data.myInfo).to.have.deep.property('job').that.is.an('number');
expect(res.data.myInfo).to.have.deep.property('auth').that.is.an('number');
expect(res.data).to.have.deep.property('structure').that.is.an('array');
res.data.structure.forEach(list => {
expect(list).to.have.deep.property('id').that.is.a('number');
expect(list).to.have.deep.property('lv').that.is.a('number');
});
done();
});
});
it('获取军团列表', function(done) {
pinusClient.request('battle.guildHandler.getGuildList', {page:1, showPeopleMax: true, name: ""} , (res) => {
console.log(JSON.stringify(res))

View File

@@ -0,0 +1,48 @@
// 军团建筑
export enum GUILD_STRUCTURE {
START = 1,
ARMY_CENTER = 1, // 中军大帐
EQUIP_PRODUCE = 2, // 炼器堂
BOSS = 3, // 演武台
TRAIN = 4, // 练兵场
DONATE = 5, // 捐献所
WISH_POOL = 6, // 许愿池
SHOP = 7, // 商店
END
}
// 权限
export enum GUILD_AUTH {
LEADER = 1, // 团长
MANAGER = 2, // 管理员
MEMBER = 3, // 成员
OTHERS = 4 // 未加入公会的其他人
}
// 职位
export enum GUILD_JOB {
JIANGJUN = 1,
FUJIANGJUN = 2,
XIAOWEI = 3,
SHIZHANG = 4,
WUZHANG = 5,
SHIBING = 6
}
// 操作
export enum GUILD_OPERATE {
CREATE_GUILD = 1, // 创建公会
}
// 军团状态
export enum GUILD_STATUS {
RUNNING = 1, // 运转中
DISMISSED = 2 // 解散
}
// 成员状态
export enum USER_GUILD_STATUS {
ON = 1, // 成员
QUIT = 2, // 退出
DISMISSED = 3 // 解散
}

View File

@@ -297,6 +297,7 @@ export const FILENAME = {
DIC_PVP_HERO_REWARD: 'dic_pvp_heroAccountReward',
DIC_PVP_RANK_REWARD: 'dic_pvp_rankReward',
DIC_PVP_BOX: 'dic_pvp_boxReward',
DIC_GUILD_AUTH: 'auth'
}
export const WAR_RELATE_TABLES = [
@@ -318,4 +319,4 @@ export const EQUIP_STRENGTHEN_TYPE = {
SINGLE: 1, // 单件单级强化
SINGLE_QUICK: 2, // 单件一键强化
ALL_QUICK: 3 // 武将全部装备栏一键强化
}
}

View File

@@ -4,4 +4,5 @@ export * from './constModules/calcuConst';
export * from './constModules/heroConst';
export * from './constModules/itemConst';
export * from './constModules/sysConst';
export * from './constModules/guildConst';
export * from './statusCode';

View File

@@ -104,11 +104,6 @@ export const STATUS = {
COM_BATTLE_REWARD_ERR: { code: 20627, simStr: '不能领取奖励' },
COM_BATTLE_REWARDED: { code: 20628, simStr: '奖励已领取' },
COM_BATTLE_HEROES_ERR: { code: 20629, simStr: '阵容异常' },
// PVP 20700-20799
PVP_ROLE_NOT_FOUND: { code: 20700, simStr: '未找到该对手' },
PVP_NOT_OPEN: { code: 20701, simStr: 'pvp尚未开启' },
PVP_REFRESH_CNT_REACH_MAX: { code: 20702, simStr: '刷新对手次数超过最大值' },
// 共斗藏宝图合成
COM_BLUEPRT_QUALITY_CANNOT_COMPOSE: { code: 20630, simStr: '该品质藏宝图不可合成' },
@@ -119,6 +114,19 @@ export const STATUS = {
DUNGEON_REFRESH_TIMES_LACK: { code: 20701, simStr: '购买次数不足' },
DUNGEON_TIMES_LACK: { code: 20701, simStr: '挑战次数不足' },
// PVP 20800-20899
PVP_ROLE_NOT_FOUND: { code: 20700, simStr: '未找到该对手' },
PVP_NOT_OPEN: { code: 20701, simStr: 'pvp尚未开启' },
PVP_REFRESH_CNT_REACH_MAX: { code: 20702, simStr: '刷新对手次数超过最大值' },
PVP_NOT_REACH_BOX_SCORE: {code: 20703, simStr: '未达到宝箱领取军功'},
PVP_BOX_IS_GOT: {code: 20704, simStr: '宝箱已经领取'},
PVP_CHALLENGE_TIMES_NOT_ENOUGH: {code: 20705, simStr: '挑战次数不足'},
// 军团 20900-20999
GUILD_AUTH_NOT_ENOUGH: { code: 20900, simStr: '权限不足' },
GUILD_NAME_DUP: { code: 20901, simStr: '公会名重复' },
GUILD_CREATE_ERROR: { code: 20902, simStr: '创建失败' },
// 通用 30000 - 30099
DIC_DATA_NOT_FOUND: { code: 30000, simStr: '数据表未找到' },
ROLE_MATERIAL_NOT_ENOUGH: { code: 30001, simStr: '材料数量不足' },
@@ -183,10 +191,6 @@ export const STATUS = {
ROLE_SCHOOL_POSITION_LOCKED: {code: 30604, simStr: '该位置未解锁'},
ROLE_SCHOOL_POSITION_UNLOCK_NOT_NEED: {code: 30605, simStr: '该位置已解锁'},
ROLE_SCROLL_REACH_MAX: {code: 30606, simStr: '已经升到可以升的最高等级'},
// pvp 30800-30899
PVP_NOT_REACH_BOX_SCORE: {code: 30800, simStr: '未达到宝箱领取军功'},
PVP_BOX_IS_GOT: {code: 30801, simStr: '宝箱已经领取'},
PVP_CHALLENGE_TIMES_NOT_ENOUGH: {code: 30802, simStr: '挑战次数不足'},
// 社交相关状态 40000 - 49999
// 运营模块相关状态 50000 - 59999

View File

@@ -1,6 +1,8 @@
import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType, Ref } from '@typegoose/typegoose';
import Role from './Role';
import { genCode } from '../pubUtils/util';
import { GUILD_STRUCTURE, GUILD_STATUS } from '../consts';
class Structure {
@prop({ required: true })
@@ -11,8 +13,9 @@ class Structure {
@index({ roleId: 1 })
export default class Guild extends BaseModel {
@prop({ required: true })
code: string;
code: string;
@prop({ required: true })
name: string;
@@ -27,10 +30,10 @@ export default class Guild extends BaseModel {
peopleNum: number;
@prop({ required: true })
leader: Ref<Role>;
leader: Ref<Role>;
@prop({ required: true, default: true })
isAuto: boolean;
isAuto: boolean;
@prop({ required: true, default: 0 })
ceCondition: number;
@@ -59,15 +62,42 @@ export default class Guild extends BaseModel {
@prop({ required: true, type: String, default: [] })
members: string[]; // 军团成员的roleId用于增加战力的时候加入总战力
@prop({ required: true, type: Structure, default: [] })
@prop({ required: true, type: Structure, default: getInitStructure(), _id: false })
structure: Structure[]
@prop({ required: true })
status:number;
@prop({ required: true, default: GUILD_STATUS.RUNNING, enum: GUILD_STATUS })
status: number;
public static async createGuild(params: CreateParam) {
const doc = new GuildModel();
const update = Object.assign(doc.toJSON(), params);
delete update._id;
const code = genCode(6);
const result: GuildType = await GuildModel.findOneAndUpdate({ code }, update, { upsert: true, new: true })
.select('code name icon notice introduce lv fund peopleNum manageNum activeDaily activeWeekly ceCondition isAuto leader structure')
.populate('leader', 'name sHid headHid lv updatedAt', 'Role')
.lean();
return result;
}
public static async checkName(name: string) {
const result = await GuildModel.findOne({ name, status: 1 }).lean();
return !!result;
}
}
export const GuildModel = getModelForClass(Guild);
export interface GuildType extends Pick<DocumentType<Guild>, keyof Guild> { };
export type GuildUpdateParam = Partial<GuildType>; // 将所有字段变成可选项
export type GuildUpdateParam = Partial<GuildType>; // 将所有字段变成可选项
type CreateParam = Pick<GuildType, 'name'|'icon'|'notice'|'leader'|'members'|'ce'>
function getInitStructure() {
let structure = new Array<Structure>();
for (let id = GUILD_STRUCTURE.START; id < GUILD_STRUCTURE.END; id++) {
structure.push({ id, lv: 1 });
}
return structure;
}

View File

@@ -1,6 +1,8 @@
import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType, Ref } from '@typegoose/typegoose';
import Role from './Role';
import Guild from './Guild';
import { GUILD_AUTH, USER_GUILD_STATUS, GUILD_JOB } from '../consts';
class ActiveRecord {
@prop({ required: true })
@@ -20,10 +22,13 @@ export default class UserGuild extends BaseModel {
@prop({ required: true })
role: Ref<Role>;
@prop({ required: true, default: 0 })
@prop({ required: true })
guild: Ref<Guild>;
@prop({ required: true, default: GUILD_AUTH.MEMBER, enum: GUILD_AUTH })
auth: number;
@prop({ required: true, default: 0 })
@prop({ required: true, default: GUILD_JOB.SHIBING, enum: GUILD_JOB })
job: number;
@prop({ required: true, default: 0 })
@@ -32,7 +37,7 @@ export default class UserGuild extends BaseModel {
@prop({ required: true, default: 0 })
honourWeek: number;
@prop({ required: true, default: 0 })
@prop({ required: true, default: USER_GUILD_STATUS.ON, enum: USER_GUILD_STATUS})
status: number;
@prop({ required: true, type: ActiveRecord, default: [] })
@@ -41,9 +46,26 @@ export default class UserGuild extends BaseModel {
@prop({ required: true, default: new Date() })
refTimeWeekly: number;
public static async getMyGuild(roleId: string) {
const myGuild: UserGuildType = await UserGuildModel.findOne({ roleId, status: USER_GUILD_STATUS.ON }).populate('guild').lean();
return myGuild||{ auth: GUILD_AUTH.OTHERS };
}
public static async createUserGuild(params: UserGuildCreateParam) {
const doc = new UserGuildModel();
const update = Object.assign(doc.toJSON(), params);
delete update._id;
const result: UserGuildType = await UserGuildModel.findOneAndUpdate({ guildCode: params.guildCode, status: USER_GUILD_STATUS.ON }, update, { upsert: true, new: true })
.select('honour job auth')
.lean();
return result;
}
}
export const GuildModel = getModelForClass(UserGuild);
export const UserGuildModel = getModelForClass(UserGuild);
export interface GuildType extends Pick<DocumentType<UserGuild>, keyof UserGuild> { };
export type GuildUpdateParam = Partial<GuildType>; // 将所有字段变成可选项
export interface UserGuildType extends Pick<DocumentType<UserGuild>, keyof UserGuild> { };
export type UserGuildUpdateParam = Partial<UserGuildType>; // 将所有字段变成可选项
type UserGuildCreateParam = Pick<UserGuildType, 'guildCode'|'roleId'|'role'|'guild'|'auth'|'job'>;

View File

@@ -43,6 +43,8 @@ import { dicGkPvp, dicGkPvps } from './dictionary/DicGkPvp';
import { dicHeroRewads } from './dictionary/DicPvpHeroReward';
import { dicRankRewads, dicRankMax } from './dictionary/DicPvpRankReward';
import { dicPvpBoxs } from './dictionary/DicPvpBox';
import { dicGuildAuth } from './dictionary/DicGuildAuth';
export const gameData = {
blurprtCompose: dicBlueprtCompose,
blueprtPossibility: dicBlueprtPossibility,
@@ -102,6 +104,7 @@ export const gameData = {
pvpRankRewards: dicRankRewads,
pvpBoxs: dicPvpBoxs,
pvpRankMax: dicRankMax,
guildAuth: dicGuildAuth
};
// 在此提供一些原先在gamedata中提供的方法以便更方便获取gameData数据

View File

@@ -35,3 +35,6 @@ export const PVP = {
PVP_OPPONENT_FREEREFRESH: 3, // pvp挑战对手每日免费刷新次数
PVP_WINREWARD_UPLIMIT: 10, // 连胜奖励军功加成上限
};
export const GUILD = {
GUILD_CREATE_COST: 10, // 创建公会消耗元宝
};

View File

@@ -0,0 +1,23 @@
// 公会权限
import { readJsonFile, parseNumberList } from '../util'
import { FILENAME } from '../../consts'
export interface DicGuildAuth {
// id
readonly id: number;
// 权限 TODO 策划字段未定
readonly auths: number[];
}
const str = readJsonFile(FILENAME.DIC_GUILD_AUTH);
let arr = JSON.parse(str);
export const dicGuildAuth = new Map<number, number[]>();
arr.forEach(o => {
let auths = parseNumberList(o.auths)
dicGuildAuth.set(o.id, auths);
});
arr = undefined;

View File

@@ -5,7 +5,7 @@ import { ItemModel } from '../db/Item';
import { EquipModel, RandSe, Holes } from './../db/Equip';
import { BagInter, EquipInter } from './interface';
import { gameData } from './data';
import { RANDOM_SE_COUNT, FIX_ATTRIBUTES_RAN, ITID } from '../consts';
import { RANDOM_SE_COUNT, FIX_ATTRIBUTES_RAN, ITID, CURRENCY_BY_TYPE, CURRENCY_TYPE } from '../consts';
import { getRandValueByMinMax, getRandEelm } from './util';
import { findWhere } from 'underscore';
@@ -59,3 +59,11 @@ export async function addEquips(roleId: string, roleName: string, weapon: EquipI
const equip = await EquipModel.createEquip({roleId, roleName, id, name, quality, suitId, randRange, ePlaceId: type, randSe, holes, hid});
return equip
}
/**
* @description 获取元宝物品 { id, count }
* @param count 元宝数量
*/
export function getGoldObject(count: number) {
return { id: CURRENCY_BY_TYPE.get(CURRENCY_TYPE.GOLD), count};
}

View File

@@ -0,0 +1 @@
[{"id": 1, "auths": "4"}]