添加抽卡的方法

This commit is contained in:
zhl 2021-01-08 17:32:32 +08:00
parent c6714648d4
commit 9394e0def8
3 changed files with 896 additions and 2 deletions

View File

@ -19,6 +19,7 @@ const fs = require('fs');
const join = require('path').join;
let config: Config = require('../config/config.json');
require('./common/Extend');
export class ApiServer {
server: FastifyInstance<Server, IncomingMessage, ServerResponse>;

863
src/common/Extend.ts Normal file
View File

@ -0,0 +1,863 @@
/**
* 0
* @param value 0
* @param length
* @return 0
*/
function zeroize(value: number | string, length: number = 2): string {
let str = "" + value;
let zeros = "";
for (let i = 0, len = length - str.length; i < len; i++) {
zeros += "0";
}
return zeros + str;
}
/****************************************扩展Object****************************************/
interface Object {
/**
*
* key value
*
* @memberOf Object
*/
clone?(): Object;
/**
* to
* @param to
*/
copyto?(to: Object):void;
/**
*
* @param property
*/
getPropertyDescriptor?(property: string): PropertyDescriptor;
zssign?(target: any): any;
}
Object.defineProperties(Object.prototype, {
clone: {
value: function () {
let o = {};
for (let n in this) {
// @ts-ignore
o[n] = this[n];
}
return o;
},
writable: true
},
getPropertyDescriptor: {
value: function (property: string): any {
let data = Object.getOwnPropertyDescriptor(this, property);
if (data) {
return data;
}
let prototype = Object.getPrototypeOf(this);
if (prototype) {
return prototype.getPropertyDescriptor(property);
}
return;
},
writable: true
},
copyto: {
value: function (to: Object) {
for (let p in this) {
if (!(p in to)) { // 本身没有这个属性
// @ts-ignore
to[p] = this[p];
} else {
let data: PropertyDescriptor = to.getPropertyDescriptor(p);
if (data) {
if (data.set || data.writable) {// 可进行赋值
// @ts-ignore
to[p] = this[p];
}
}
}
}
},
writable: true
},
zssign: {
value: function (target: Object) {
if (target === undefined || target === null) {
throw new TypeError('Cannot convert undefined or null to object');
}
let output = Object(target);
for (let nextKey in this) {
if (!(nextKey in output)) { // 本身没有这个属性
output[nextKey] = this[nextKey];
}
// else {
// let data: PropertyDescriptor = output.getPropertyDescriptor(nextKey);
// if (data) {
// if (data.set || data.writable) {// 可进行赋值
// output[nextKey] = this[nextKey];
// }
// }
// }
}
return output;
},
writable: true
}
});
/****************************************扩展Math****************************************/
interface Math {
/**
*
* @param value
* @param min
* @param max
*/
clamp?(value: number, min: number, max: number): number;
/**
* [min,max)
*/
random2?(min: number, max: number): number;
/**
*
* Math.PI / 180
* @type {number}
* @memberOf Math
*/
DEG_TO_RAD: number;
/**
*
* 180 / Math.PI
*/
RAD_TO_DEG: number;
/**
*
*/
PI2: number;
/**
* 90°
*
* @type {number}
* @memberOf Math
*/
PI_1_2: number;
}
Math.DEG_TO_RAD = Math.PI / 180;
Math.RAD_TO_DEG = 180 / Math.PI;
Math.PI2 = 2 * Math.PI;
Math.PI_1_2 = Math.PI * .5;
Math.clamp = (value, min, max) => {
if (value < min) {
value = min;
}
if (value > max) {
value = max;
}
return value;
}
Math.random2 = (min, max) => {
return min + Math.random() * (max - min);
}
/****************************************扩展Number********************************************/
interface Number {
/**
* 0
* @param length
* @return 0
*/
zeroize?(length: number): string;
/**
* `min` `max`minmax
* [min,max]
*
* @param {number} min
* @param {number} max
* @returns {boolean}
* @memberof Number
*/
between?(min: number, max: number): boolean;
}
Object.defineProperties(Number.prototype, {
zeroize: {
value: function (this: number, length: number) { return zeroize(this, length) },
writable: true
},
between: {
value: function (this: number, min: number, max: number) { return min <= this && max >= this },
writable: true
}
});
/****************************************扩展String****************************************/
interface String {
/**
* {0}{1}{2}{a} {b}obj对应key替换key的数据替换
*/
substitute?(...args: any): string;
substitute?(args: any[]): string;
/**
* 0
* @param length
* @return 0
*/
zeroize?(length: number): string;
/**
*
* <font color="#ff0000">hash的字符串并不一定唯一</font>
*/
hash?(): number;
/**
*
*/
trueLength?(): number;
/**
*
* */
cnLength?(): number;
/**
*
* */
versionCompare?(target: string): number;
}
Object.defineProperties(String.prototype, {
zeroize: {
value: function (length: number) { return zeroize(this, length) },
writable: true
},
substitute: {
value: function (this: string) {
let len = arguments.length;
if (len > 0) {
let obj: IArguments;
if (len == 1) {
obj = arguments[0];
if (typeof obj !== "object") {
obj = arguments;
}
} else {
obj = arguments;
}
if ((obj instanceof Object) && !(obj instanceof RegExp)) {
return this.replace(/\{(?:%([^{}]+)%)?([^{}]+)\}/g, function (match: string, handler: string, key: string) {
//检查key中是否为%开头,如果是,则尝试按方法处理
// @ts-ignore
let value = obj[key];
if (handler) {//如果有处理器,拆分处理器
let func = String.subHandler[handler];
if (func) {
value = func(value);
}
}
return (value !== undefined) ? '' + value : match;
});
}
}
return this.toString();//防止生成String对象ios反射String对象会当成一个NSDictionary处理
},
writable: true
},
hash: {
value: function () {
let len = this.length;
let hash = 5381;
for (let i = 0; i < len; i++) {
hash += (hash << 5) + this.charCodeAt(i);
}
return hash & 0x7fffffff;
},
writable: true
},
trueLength: {
value: function () {
let arr: string[] = this.match(/[\u2E80-\u9FBF]/ig);
return this.length + (arr ? arr.length : 0);
},
writable: true
},
cnLength: {
value: function () {
let arr: string[] = this.match(/[\u2E80-\u9FBF]/ig);
return arr ? arr.length : 0;
},
writable: true
},
versionCompare: {
value: function (target: string): number {
const GTR = 1; //大于
const LSS = -1; //小于
const EQU = 0; //等于
if (!target) {
return GTR;
}
let v1arr = String(this).split(".").map(function (a) {
return parseInt(a);
});
let v2arr = String(target).split(".").map(function (a) {
return parseInt(a);
});
let arrLen = Math.max(v1arr.length, v2arr.length);
let result;
//排除错误调用
if (this == undefined || target == undefined) {
throw new Error();
}
//检查空字符串,任何非空字符串都大于空字符串
if (this.length == 0 && target.length == 0) {
return EQU;
} else if (this.length == 0) {
return LSS;
} else if (target.length == 0) {
return GTR;
}
//循环比较版本号
for (let i = 0; i < arrLen; i++) {
result = versionComp(v1arr[i], v2arr[i]);
if (result == EQU) {
continue;
} else {
break;
}
}
return result;
function versionComp(n1: number, n2: number) {
if (typeof n1 != "number") {
n1 = 0;
}
if (typeof n2 != "number") {
n2 = 0;
}
if (n1 > n2) {
return GTR;
} else if (n1 < n2) {
return LSS;
} else {
return EQU;
}
}
},
writable: true
}
});
interface StringConstructor {
/**
* 0
* @param value 0
* @param length
* @return 0
*/
zeroize?: (value: number, length: number) => string;
/**
* substitute的回调函数
*
* @type {Readonly<{ [index: string]: { (input: any): string } }>}
* @memberOf StringConstructor
*/
subHandler?: Readonly<{ [index: string]: { (input: any): string } }>;
}
String.zeroize = zeroize;
/****************************************扩展Date****************************************/
interface Date {
/**
*
*
* @param {string} mask
* @param {boolean} [local] UTC时间显示
* @returns {string}
*/
format(mask: string, local?: boolean): string;
}
Object.defineProperties(Date.prototype, {
format: {
value: function (mask: string, local?: boolean) {
let d: Date = this;
// @ts-ignore
return mask.replace(/"[^"]*"|'[^']*'|(?:d{1,2}|m{1,2}|yy(?:yy)?|([hHMs])\1?)/g, function ($0: string) {
switch ($0) {
case "d": return gd();
case "dd": return zeroize(gd());
case "M": return gM() + 1;
case "MM": return zeroize(gM() + 1);
case "yy": return (gy() + "").substr(2);
case "yyyy": return gy();
case "h": return gH() % 12 || 12;
case "hh": return zeroize(gH() % 12 || 12);
case "H": return gH();
case "HH": return zeroize(gH());
case "m": return gm();
case "mm": return zeroize(gm());
case "s": return gs();
case "ss": return zeroize(gs());
default: return $0.substr(1, $0.length - 2);
}
});
function gd() { return local ? d.getDate() : d.getUTCDate() }
function gM() { return local ? d.getMonth() : d.getUTCMonth() }
function gy() { return local ? d.getFullYear() : d.getUTCFullYear() }
function gH() { return local ? d.getHours() : d.getUTCHours() }
function gm() { return local ? d.getMinutes() : d.getUTCMinutes() }
function gs() { return local ? d.getSeconds() : d.getUTCSeconds() }
},
writable: true
}
});
/****************************************扩展Array****************************************/
const enum ArraySort {
/**
*
*/
ASC = 0,
/**
*
*/
DESC = 1
}
interface ArrayConstructor {
// binaryInsert<T>(partArr: T[], item: T, filter: { (tester: T, ...args): boolean }, ...args);
SORT_DEFAULT: { number: 0, string: "", boolean: false };
}
/**
* Array排序时undefined
*/
Array.SORT_DEFAULT = {
number: 0,
string: "",
boolean: false
}
Object.freeze(Array.SORT_DEFAULT);
interface Array<T> {
/**
*
*
* @param {T} t
* @returns {number}
*
* @member Array
*/
pushOnce?(t: T): number;
/**
*
*
* @param {T} t
* @returns {boolean} true
* false
*/
remove?(t: T): boolean;
/**
*
* ,
* @param {(keyof T)[]} kArr
* @param {(boolean[] | ArraySort[])} [dArr]
* @returns {this}
*
* @member Array
*/
multiSort?(kArr: (keyof T)[], dArr?: boolean[] | ArraySort[]): this;
/**
*
*
* @param {string} [key]
* @param {boolean} [descend]
*
* @member Array
*/
doSort?(key?: keyof T, descend?: boolean | ArraySort): this;
doSort?(descend?: boolean | ArraySort, key?: keyof T): this;
/**
* to
* to的数组长度会和当前数组一致
*
* @template T
* @param {Array<T>} to
*/
cloneTo?<T>(to: Array<T>):void;
/**
* to中
*
* @template T
* @param {Array<T>} to
*
* @member ArrayConstructor
*/
appendTo?<T>(to: Array<T>):void;
/**
* index位置的元素, slice效率高
* @param index
*/
spliceOne?(index: number): boolean;
/**
*
*/
randomSort?():void;
/**
* object
* @param obj obj | | child字段的值 | child字段的数组
* @param child
*/
contains?<T>(obj: T | T[] | {} | {}[], child?: string): boolean;
/**
*
* @param arr
*/
randomInsert?<T>(arr: Array<T>):void;
/**
* n个元素
* @param count
*/
randomGet?<T>(count?: number):T[];
/**
* 1
*/
randomOne?<T>():T;
/**
* n个元素
* @param count
*/
randomRemove?<T>(count?: number):T[];
/**
* n位
* @param n n > 0 , n<0 左移
*/
moveElement?<T>(n: number): T[];
/**
*
* @param arr
*/
union?<T>(arr: T[]): T[];
/**
*
* @param arr
*/
intersect?<T>(arr: T[]): T[];
/**
* arr的差集
* @param arr
*/
difference?<T>(arr: T[]): T[];
}
Object.defineProperties(Array.prototype, {
cloneTo: {
value: function <T>(this: T[], b: any[]) {
b.length = this.length;
let len = this.length;
b.length = len;
for (let i = 0; i < len; i++) {
b[i] = this[i];
}
},
writable: true
},
appendTo: {
value: function <T>(this: T[], b: any[]) {
let len = this.length;
for (let i = 0; i < len; i++) {
b.push(this[i]);
}
},
writable: true
},
pushOnce: {
value: function <T>(this: T[], t: T) {
let idx = this.indexOf(t);
if (!~idx) {
idx = this.length;
this[idx] = t;
}
return idx;
},
writable: true
},
remove: {
value: function <T>(this: T[], t: T) {
let idx = this.indexOf(t);
if (~idx) {
this.splice(idx, 1);
return true;
}
return false;
},
writable: true
},
doSort: {
value: function () {
let key: string, descend: boolean;
let len = arguments.length;
for (let i = 0; i < len; i++) {
let arg = arguments[i];
let t = typeof arg;
if (t === "string") {
key = arg;
} else {
descend = !!arg;
}
}
if (key) {
return this.sort((a: any, b: any) => descend ? b[key] - a[key] : a[key] - b[key]);
} else {
return this.sort((a: any, b: any) => descend ? b - a : a - b);
}
},
writable: true
},
multiSort: {
value: function (kArr: string[], dArr?: boolean[] | boolean) {
let isArr = Array.isArray(dArr);
return this.sort((a: any, b: any): number => {
const def = Array.SORT_DEFAULT;
for (let idx = 0, len = kArr.length; idx < len; idx++) {
let key = kArr[idx];
// @ts-ignore
let mode = isArr ? !!dArr[idx] : !!dArr;
let av = a[key];
let bv = b[key];
let typea = typeof av;
let typeb = typeof bv;
if (typea == "object" || typeb == "object") {
return 0;
}
else if (typea != typeb) {
if (typea == "undefined") {
// @ts-ignore
bv = def[typeb];
} else if (typeb == "undefined") {
// @ts-ignore
av = def[typea];
}
else {
return 0;
}
}
if (av < bv) {
return mode ? 1 : -1;
} else if (av > bv) {
return mode ? -1 : 1;
} else {
continue;
}
}
return 0;
});
},
writable: true
},
spliceOne: {
value: function (index: number): boolean {
if (index === -1 || index >= this.length) {
return false;
}
const len = this.length - 1;
for (let i = index; i < len; i++) {
this[i] = this[i + 1];
}
this.length = len;
return true;
},
writable: true
},
randomSort: {
value: function<T> () {
for (let j, x, i = this.length; i; j = (Math.random() * i) | 0, x = this[--i], this[i] = this[j], this[j] = x) {
;
}
},
writable: true
},
contains: {
value: function<T> (obj: T | T[] | {} | {}[], child?: string): boolean {
let result = false;
if (child) {
const isArr = Array.isArray(obj);
if (isArr) {
// @ts-ignore
if (obj[0].hasOwnProperty(child)) {
let set0 = new Set();
// @ts-ignore
for (let s of obj) {
// @ts-ignore
set0.add(s[child]);
}
// @ts-ignore
let set1 = new Set(this.filter (x => set0.has(x)));
return set0.size === set1.size;
} else {
// @ts-ignore
let set0 = new Set(obj);
let set1 = new Set(this.filter ((x: {}) => set0.has(x)));
return set1.size === set0.size;
}
} else {
if (obj.hasOwnProperty(child)) {
for (let sub of this) {
if (sub.hasOwnProperty(child)) {
// @ts-ignore
if (sub[child] === obj[child]) {
result = true;
break;
}
}
}
} else {
for (let sub of this) {
if (sub.hasOwnProperty(child)) {
// @ts-ignore
if (sub[child] === obj) {
result = true;
break;
}
}
}
}
}
} else {
// 不指定 比较字段 的话, 只处理2种情况
// 1: obj 为数组
// 2: obj 不是数组
if (Array.isArray(obj)) {
let set0 = new Set(obj);
// @ts-ignore
let set1 = new Set(this.filter (x => set0.has(x)));
return set1.size === set0.size;
} else {
let idx = this.indexOf(obj);
return !!(~idx);
}
}
return result;
},
writable: true
},
randomInsert: {
value: function<T>(arr: Array<T>) {
const length = this.length;
arr.forEach(value => {
this.splice(Math.random() * length, 0 , value);
})
},
writable: true
},
randomGet: {
value: function<T>(count: number = 1):T[] {
let shuffled: T[] = this.slice(0), i = this.length, min = i - count, temp, index;
if (min < 0) {
return shuffled;
}
while (i-- > min) {
index = Math.floor((i + 1) * Math.random());
temp = shuffled[index];
shuffled[index] = shuffled[i];
shuffled[i] = temp;
}
return shuffled.slice(min);
},
writable: true
},
randomOne: {
value: function<T>(): T {
let results = this.randomGet(1);
if (results.length > 0) {
return results[0];
} else {
return null;
}
},
writable: true
},
randomRemove: {
value: function<T>(count: number = 1):T[] {
let result = [];
while (count -- > 0 && this.length > 0) {
let index = Math.random() * this.length | 0;
result.push(...this.splice(index, 1));
}
return result;
},
writable: true
},
moveElement: {
value: function<T> (n: number): T[] {
if (Math.abs(n) > this.length) n = n % this.length;
return this.slice(-n).concat(this.slice(0, -n));
},
writable: true
},
union: {
value: function<T> (this: T[], b: any[]): T[] {
let a = this.concat(b);
return [...new Set(a)];
},
writable: true
},
intersect: {
value: function<T> (this: T[], b: any[]): T[] {
let set0 = new Set(b);
let set1 = new Set(this.filter (x => set0.has(x)));
return [...set1];
},
writable: true
},
difference: {
value: function<T> (this: T[], b: any[]): T[] {
let set0 = new Set(b);
let set1 = new Set(this.filter(x => !set0.has(x)));
return [...set1];
},
writable: true
}
});

View File

@ -4,6 +4,7 @@ import {CardGroup} from "../models/CardGroup";
import {ZError} from "../common/ZError";
import {Card} from "../models/subdoc/Card";
import {MoneyTypeConst} from "../constants/MoneyTypeConst";
import {BaseConst} from "../constants/BaseConst";
export default class CardController extends BaseController {
@router('post /api/:accountid/card_group/:heroid')
@ -102,8 +103,37 @@ export default class CardController extends BaseController {
}
account.moneys.set(MoneyTypeConst.CARD_SCROLL, money - count);
// TODO: 随机取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));
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;
}
results.push(data);
}
account.moneys.set(MoneyTypeConst.HERO_EXP, expHero);
account.cards = totalCards;
await account.save();
return {};
return results;
}
}