diff --git a/docs/api.md b/docs/api.md index d3b1ce6..01b1ad1 100644 --- a/docs/api.md +++ b/docs/api.md @@ -178,64 +178,33 @@ 根据errcode判断成功or失败 -### ~~7. 解锁英雄~~ + + +### 8. 抽卡 1. Method: POST -2. URI: /api/:accountid/hero/unlock/:heroid +2. URI: /api/:accountid/card/draw | 字段 | 说明 | | -------- | -------------------------------------- | | accountid | 帐号id | -| heroid | 英雄id | + > POST参数 | 字段 | 说明 | | -------- | -------------------------------------- | -| type | 类型 0: 碎片, 1: 试用 | - - - - - -3. Response: JSON - -> 说明: 解锁成功的话, 会返回当前解锁英雄的数据 - - -```js -[{ - heroid: 1022, // 英雄id - owned: true, // 是否已拥有 - ban: false, // 是否被禁用 - usetype: 1, // 赛季专属, 0: 通用, 1: 赛季排位专用, 2: 匹配专用 - free: false, // 是否免费 - trial: false, // 是否是试用 - trial_expire: 1609919293 // 试用到期时间, 0: 说明是永久 - level: 1, // 等级 - exp: 0, // 当前的经验值 -}] -``` - - - -### 8. 抽卡 -1. Method: POST -2. URI: /api/:accountid/card/draw/:count - -| 字段 | 说明 | -| -------- | -------------------------------------- | -| accountid | 帐号id | -| count | 抽卡数量 | +| count | 类型 1 或 10 | +|itemid| 抽卡使用的物品id | 3. Response: JSON ```js [{ - cardid: 1022, // 卡牌id - isnew: true, // 是否是新获得的卡 - expdust: '', // 分解可获得的英雄经验的item id - dustcount: 100 // 可获得数量 + id: 11022, // 卡牌id + used: 1, // 是否已经自动激活卡或英雄, 1: 已自动激活 0: 未激活 + heroid: 111, // 激活的英雄id, 可能为空 + cardid: 100 // 激活的卡id, 可能为空 }] ``` @@ -521,6 +490,44 @@ ``` +### 3. 解锁英雄 +1. Method: POST +2. URI: /svr/:accountid/hero/unlock/:heroid + +| 字段 | 说明 | +| -------- | -------------------------------------- | +| accountid | 帐号id | +| heroid | 英雄id | +> POST参数 + + +| 字段 | 说明 | +| -------- | -------------------------------------- | +| type | 类型 0: 碎片, 1: 试用 | + + + + + +3. Response: JSON + +> 说明: 解锁成功的话, 会返回当前解锁英雄的数据 + + +```js +[{ + heroid: 1022, // 英雄id + owned: true, // 是否已拥有 + ban: false, // 是否被禁用 + usetype: 1, // 赛季专属, 0: 通用, 1: 赛季排位专用, 2: 匹配专用 + free: false, // 是否免费 + trial: false, // 是否是试用 + trial_expire: 1609919293 // 试用到期时间, 0: 说明是永久 + level: 1, // 等级 + exp: 0, // 当前的经验值 +}] +``` + diff --git a/src/controllers/AccountController.ts b/src/controllers/AccountController.ts index d048900..ba4371c 100644 --- a/src/controllers/AccountController.ts +++ b/src/controllers/AccountController.ts @@ -7,6 +7,7 @@ import { BaseConst } from '../constants/BaseConst' import { Hero } from '../models/subdoc/Hero' import { CardGroup } from '../models/CardGroup' import { BagItem, ItemType } from '../models/BagItem' +import { addHeroDefaultCardGroup } from '../dao/CardGroupDao' export default class AccountController extends BaseController { @role('anon') @@ -48,27 +49,7 @@ export default class AccountController extends BaseController { hero.exp = 0 if (!account.heros.has(cfg.id + '')) { account.heros.set(cfg.id + '', hero) - let cardgroup = new CardGroup({}) - let cards: Card[] = [] - for (let i = 1; i <= 4; i++) { - const cardid = cfg[`follower${ i }id`] - const owned = cardMap.has(cardid) - const card = new Card() - card.cardid = cardid - card.owned = owned - card.ban = false - card.usetype = 0 - card.free = !owned - card.free_expire = 0 - card.time = Date.now() - cards.push(card) - } - cardgroup.accountid = account.id - cardgroup.heroid = cfg.id - cardgroup.selected = false - cardgroup.isdefault = true - cardgroup.cards = cards - await cardgroup.save() + await addHeroDefaultCardGroup(accountid, hero.heroid, cardMap) } } } diff --git a/src/controllers/CardController.ts b/src/controllers/CardController.ts index ee54078..5de5444 100644 --- a/src/controllers/CardController.ts +++ b/src/controllers/CardController.ts @@ -7,6 +7,10 @@ import { MoneyTypeConst } from '../constants/MoneyTypeConst' import { BaseConst } from '../constants/BaseConst' import { BagItem, ItemType } from '../models/BagItem' import ItemCtrl from '../logic/ItemCtrl' +import { error } from '../common/Debug' +import { ItemFuncCfg } from '../cfg/parsers/ItemFuncCfg' +import { addHeroDefaultCardGroup } from '../dao/CardGroupDao' +import { ItemInfo } from '../logic/ItemDef' export default class CardController extends BaseController { @router('post /api/:accountid/card_group/:heroid') @@ -123,56 +127,102 @@ export default class CardController extends BaseController { return {} } - @router('post /api/:accountid/card/draw/:count') + @router('post /api/:accountid/card/draw') async drawCard(req: any) { - let { count } = req.params - if (count < 10) { - count = 1 + let { count, accountid, itemid } = req.params + count = count << 0 + itemid = itemid << 0 + if (count != 10 && count != 1) { + throw new ZError(101, '参数不正确') } - if (count > 10) { - count = 10 + let cfg: ItemFuncCfg = count == 10 ? + global.$cfg.get(BaseConst.ITEMFUNC).get(90002): + global.$cfg.get(BaseConst.ITEMFUNC).get(90001) + if (!cfg) { + error(`抽卡 ${accountid} : [${count}, 无法找到抽卡配置`) + throw new ZError(102, '无法找到对应的配置') + } + let itemInfo = ItemCtrl.getItemsByInfo(cfg.consume1) + if (count == 1 && itemInfo.length == 0) { + throw new ZError(103, '无法找到对应的配置') + } + if (count == 1 && itemInfo[0].id !== itemid) { + throw new ZError(104, '解锁物品与配置不符') + } + if (count == 10) { + if (itemid != itemInfo[0].id) { + itemInfo = ItemCtrl.getItemsByInfo(cfg.consume2) + if (itemInfo.length == 0 || itemInfo[0].id != itemid) { + throw new ZError(104, '解锁物品与配置不符') + } + } + } + let record = await BagItem.findOne({accountid, itemid}) + if (!record || record.count < count) { + throw new ZError(105, '解锁物品数量不足') + } + const items: ItemInfo[] = [] + for (let z = 0 ; z < count; z ++) { + items.push(ItemCtrl.getItemsByInfo(cfg.get)[0]) } let account = req.user - if (!account.moneys.has(MoneyTypeConst.CARD_SCROLL)) { - throw new ZError(101, '卷轴不足') - } - let money = account.moneys.get(MoneyTypeConst.CARD_SCROLL) - if (money < count) { - throw new ZError(101, '卷轴不足') - } - account.moneys.set(MoneyTypeConst.CARD_SCROLL, money - count) - - // TODO: 根据配置的概率获取卡 - let cardMap = global.$cfg.get(BaseConst.UNIT) - let cards: any[] = [] - for (let [id, card] of cardMap) { - if (card.unittypei_id == 2) { - cards.push(card) - } - } - let cardsgetd: number[] = cards.randomGet(count).map((o: any) => o.id) - let totalCards = account.cards.union(cardsgetd) - let dulpSet = new Set(account.cards.intersect(cardsgetd)) + const cfgMap = global.$cfg.get(BaseConst.ITEMCARD) let results: any = [] - let expHero = account.moneys.get(MoneyTypeConst.HERO_EXP) || 0 - //TODO: 根据配置设置每张卡分解后得到的经验 - const expPreCard = 10 - for (let id of cardsgetd) { - let data: any = { id } - if (dulpSet.has(id)) { - data.isnew = false - data.expdust = MoneyTypeConst.HERO_EXP - data.dustcount = expPreCard - expHero += expPreCard - } else { - data.isnew = true + const cardMap = account.cardMap + for (let item of items) { + if (item.type != ItemType.CARD) { + results.push({ + id: item.id, + used: 0, + count: item.count + }); + continue + } + if (item.type == ItemType.CARD &&!cfgMap.has(item.id)) { + error(`抽卡 ${item.id} 的配置不存在`) + continue + } + const data = cfgMap.get(item.id) + if (data.unlocking >= 30000 ) { // 英雄 + for (let i = 0; i < item.count; i ++) { + let result = account.unlockHero(data.unlocking, data.unlockingtimes) + if (result == 1) { + await addHeroDefaultCardGroup(accountid, data.unlocking, cardMap) + } + if (result > 0) { + results.push({ + id: item.id, + used: 1, + heroid: data.unlocking + }) + } else { + results.push({ + id: item.id, + used: 0 + }) + } + } + } else { // 随从卡 + for (let i = 0; i < item.count; i ++) { + const result = account.unlockCard(data.unlocking, data.unlockingtimes) + if (result > 0) { + results.push({ + id: item.id, + used: 1, + cardid: data.unlocking + }) + } else { + results.push({ + id: item.id, + used: 0, + }) + } + } } - results.push(data) } - - account.moneys.set(MoneyTypeConst.HERO_EXP, expHero) - account.cards = totalCards await account.save() + record.count -= count + await record.save() return results } diff --git a/src/controllers/HeroController.ts b/src/controllers/HeroController.ts index 1868f12..2f8399e 100644 --- a/src/controllers/HeroController.ts +++ b/src/controllers/HeroController.ts @@ -7,6 +7,7 @@ import { Card } from '../models/subdoc/Card' import { HeroCfg } from '../cfg/parsers/HeroCfg' import { Hero } from '../models/subdoc/Hero' import { BagItem, ItemType } from '../models/BagItem' +import { addHeroDefaultCardGroup } from '../dao/CardGroupDao' export default class HeroController extends BaseController { @router('post /api/:accountid/heros') @@ -20,7 +21,6 @@ export default class HeroController extends BaseController { return heros } - @router('post /api/:accountid/hero/unlock/:heroid') @router('post /svr/:accountid/hero/unlock/:heroid') async unlockHero(req: any) { let account = req.user @@ -30,36 +30,11 @@ export default class HeroController extends BaseController { } let hero if (!type) { - let userMoney = !req.url.startsWith('/svr') - hero = await account.unlockHero(heroid, userMoney) + hero = await account.unlockHero(heroid, 1) // 将该英雄的默认卡组添加到玩家的卡组中, // 将默认卡组里的卡添加到玩家可用卡牌中 let cardMap = account.cardMap - let cfg = global.$cfg.get(BaseConst.HERO).get(parseInt(hero.heroid)) - let cardgroup = new CardGroup({}) - let cards: Card[] = [] - for (let i = 1; i < 10; i++) { - if (!cfg[`follower${ i }id`]) { - break - } - const cardid = cfg[`follower${ i }id`] - const owned = cardMap.has(cardid) - const card = new Card() - card.cardid = cardid - card.owned = owned - card.ban = false - card.usetype = 0 - card.free = !owned - card.free_expire = 0 - card.time = Date.now() - cards.push(card) - } - cardgroup.accountid = account.id - cardgroup.heroid = hero.heroid - cardgroup.selected = false - cardgroup.isdefault = true - cardgroup.cards = cards - await cardgroup.save() + await addHeroDefaultCardGroup(account.id, hero.heroid, cardMap) await account.save() } else { hero = await account.tryHero(heroid) diff --git a/src/dao/CardGroupDao.ts b/src/dao/CardGroupDao.ts new file mode 100644 index 0000000..dc8e0c2 --- /dev/null +++ b/src/dao/CardGroupDao.ts @@ -0,0 +1,28 @@ +import { BaseConst } from '../constants/BaseConst' +import { CardGroup } from '../models/CardGroup' +import { Card } from '../models/subdoc/Card' + +export async function addHeroDefaultCardGroup(accountid: string, heroid: number, cardMap: Map) { + const heroCfg = global.$cfg.get(BaseConst.HERO).get(heroid) + let cardgroup = new CardGroup({}) + let cards: Card[] = [] + for (let i = 1; i <= 4; i++) { + const cardid = heroCfg[`follower${ i }id`] + const owned = cardMap.has(cardid) + const card = new Card() + card.cardid = cardid + card.owned = owned + card.ban = false + card.usetype = 0 + card.free = !owned + card.free_expire = 0 + card.time = Date.now() + cards.push(card) + } + cardgroup.accountid = accountid + cardgroup.heroid = heroCfg.id + cardgroup.selected = false + cardgroup.isdefault = true + cardgroup.cards = cards + await cardgroup.save() +} diff --git a/src/models/User.ts b/src/models/User.ts index 3939e34..269cf49 100644 --- a/src/models/User.ts +++ b/src/models/User.ts @@ -148,61 +148,64 @@ class UserClass extends FindOrCreate { return fc.get(70021).number + this.season_score * (fc.get(70020).number / 100 + twp) } - public async unlockHero(heroid: number, useMoney: boolean) { - if (this.heros.has(heroid + '')) { - if (!this.heros.get(heroid + '').trial) { - throw new ZError(102, '你已经解锁了该英雄') - } + public unlockHero(heroid: number, maxCount: number) { + let hero = this.heros.get(heroid + '') + let result = 0 + if (hero && !hero.trial && hero.count >= maxCount) { + return result } - if (useMoney) { - let money0 = MoneyTypeConst.getHeroShard(heroid) - let money1 = MoneyTypeConst.HERO_SHARD - let count0 = this.moneys.has(money0) ? this.moneys.get(money0) : 0 - let count1 = this.moneys.has(money1) ? this.moneys.get(money1) : 0 - // TODO:: 根据配置获取解锁英雄需要的碎片数量 - let needCount = 30 - if (count0 + count1 < needCount) { - throw new ZError(102, '碎片数量不足') - } - if (count0 > 0) { - let rest = needCount - count0 - if (rest >= 0) { - needCount = rest - this.moneys.set(money0, 0) - } else { - needCount = 0 - this.moneys.set(money0, Math.abs(rest)) - } - } - // 上面已经过滤了 count0 + count1 > needcount, 所以这里不需要判断碎片是否足够 - if (needCount > 0) { - count1 = count1 - needCount - this.moneys.set(money1, count1) - } + if (!hero) { + hero = new Hero() + hero.heroid = heroid + hero.free = false + hero.trial = false + hero.level = 1 + hero.trial_expire = 0 + hero.exp = 0 + hero.slot = 1 + hero.count = 1 + hero.time = Date.now() + } else { + hero.count += 1 } - let hero = new Hero() - hero.heroid = heroid - hero.free = false - hero.trial = false - hero.level = 1 - hero.trial_expire = 0 - hero.exp = 0 - hero.slot = 1 - hero.time = Date.now() + result = hero.count this.heros.set(heroid + '', hero) - return hero + return result + } + + public async unlockCard(cardid: number, maxCount: number) { + let card = this.cardMap.get(cardid + '') + let result = 0 + if (card && card.count >= maxCount) { + return result + } + if (!card) { + const card = new Card() + card.cardid = cardid + card.owned = true + card.ban = false + card.usetype = 0 + card.free = false + card.count = 0 + card.free_expire = 0 + card.time = Date.now() + } else { + card.count += 1 + } + this.cardMap.set(card.cardid + '', card) + return card.count } public async tryHero(heroid: number) { if (this.heros.has(heroid + '')) { throw new ZError(102, '你已经解锁了该英雄') } - //TODO:: 根据配置查看该英雄是否可使用 let hero = new Hero() hero.heroid = heroid hero.free = false hero.trial = true hero.level = 1 + hero.count = 0 hero.trial_expire = 0 hero.exp = 0 this.heros.set(heroid + '', hero) diff --git a/src/models/subdoc/Card.ts b/src/models/subdoc/Card.ts index 852c2c4..060c637 100644 --- a/src/models/subdoc/Card.ts +++ b/src/models/subdoc/Card.ts @@ -32,6 +32,13 @@ export class Card { */ @prop() public free_expire: number + + /** + * 解锁数量 + * @type {number} + */ + @prop({default: 1}) + public count: number /** * 添加时间 * @type {number} @@ -47,7 +54,8 @@ export class Card { usetype: this.usetype, free: this.free, free_expire: this.free_expire, - time: this.time + time: this.time, + count: this.count } } } diff --git a/src/models/subdoc/Hero.ts b/src/models/subdoc/Hero.ts index 79db1ba..cfb3056 100644 --- a/src/models/subdoc/Hero.ts +++ b/src/models/subdoc/Hero.ts @@ -31,10 +31,20 @@ export class Hero { */ @prop({default: 1}) public slot: number - + /** + * 第一次解锁时间 + * @type {number} + */ @prop() public time: number + /** + * 解锁数量 + * @type {number} + */ + @prop({default: 1}) + public count: number + public toJson() { let data: any = { heroid: this.heroid, @@ -46,7 +56,8 @@ export class Hero { trial_expire: this.trial_expire, slot: this.slot, time: this.time, - ban: false + ban: false, + count: this.count } data.owned = !this.trial return data