implement loot system feedback

This commit is contained in:
peter
2020-02-06 23:37:17 +01:00
parent b987974b9e
commit 5ace7357a4
22 changed files with 382 additions and 199 deletions
+7
View File
@@ -102,6 +102,13 @@ implements TableDefinitionExporter, IAdmin {
private startWebsocket(){
this.rpcServer = new RPCServer(20000, [
...this.frontworkComponents,
{
name: "debug",
exportRPCs: () => [{
name: 'dumpDb',
call: async (table) => await this.knex(table).select('*')
}]
}
], {
visibility: '0.0.0.0'
})
+2 -2
View File
@@ -1,9 +1,9 @@
import { Item, Character, SRToken, SRPriority, Spec } from "../../Types/Types"
import { Item, Character, SRToken, SRPriority, Spec, Signup } from "../../Types/Types"
export class IItemManager{
getItems: () => Promise<Item[]>
fetchItem: (name:string) => Promise<Item>
buyToken: (usertoken: string, charactername:string, itemname:string) => Promise<(SRToken & Character & Item) | void>
buyToken: (usertoken: string, charactername:string, itemname:string, signup:Signup) => Promise<(SRToken & Character & Item) | void>
setPriority: (itemname:string, priority: any) => Promise<void>
calculatePriorities: (itemname: string, character:Character) => Promise<number>
deletePriority: (priority:SRPriority) => Promise<void>
+96 -49
View File
@@ -1,9 +1,9 @@
import { T1, T2 } from "../../Types/Items";
import { T1, T2, allItems, _Tiers } from "../../Types/Items";
import { Inject, Injectable } from "../../Injector/ServiceDecorator";
import { ItemManagerFeatureIfc, ItemManagerIfc } from "./RPCInterface";
import { FrontworkComponent } from "../../Types/FrontworkComponent";
import { TableDefinitionExporter } from "../../Types/Interfaces";
import { TableDefiniton, Item, User, Character, SRToken, SRPriority, Spec } from "../../Types/Types";
import { TableDefiniton, Item, User, Character, SRToken, SRPriority, Spec, Signup } from "../../Types/Types";
import { IAdmin } from "../../Admin/Interface";
import { IItemManager } from "./Interface";
import { getLogger } from "log4js";
@@ -87,19 +87,21 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
{
name: 'tokens',
tableBuilder: (table) => {
table.primary(['characterid', 'itemid'])
table.primary(['characterid', 'itemname'])
table.integer("characterid")
table.foreign("characterid").references("id").inTable('characters')
table.integer("itemid")
table.foreign("itemid").references("id").inTable('items')
table.string("itemname")
table.foreign("itemname").references("itemname").inTable('items')
table.string("signupid").nullable()
table.foreign("signupid").references("id").inTable('signups').onDelete('SET NULL')
table.integer("level").defaultTo(1)
}
},{
name: 'priorities',
tableBuilder: (table) => {
table.increments('id').primary()
table.integer('itemid')
table.foreign('itemid').references('id').inTable('items')
table.string('itemname')
table.foreign('itemname').references('itemname').inTable('items')
table.string('race').nullable()
table.integer('specid').nullable()
table.foreign('specid').references('id').inTable('specs')
@@ -109,17 +111,17 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
},{
name: 'items',
tableBuilder: (table) => {
table.increments("id").primary()
table.string('itemname').unique().notNullable()
table.string('itemname').unique().notNullable().primary()
table.string('iconname').notNullable()
table.string('url').notNullable()
table.string('quality').defaultTo('Epic').notNullable()
table.boolean('hidden').defaultTo(false).notNullable()
table.enu('tier', _Tiers).notNullable()
}
}]
}
buyToken = async (usertoken: string, charactername:string, itemname:string): Promise<(SRToken & Character & Item) | void> => {
buyToken = async (usertoken: string, charactername:string, itemname:string, signup: Signup): Promise<(SRToken & Character & Item) | void> => {
const record = this.userManager.getUserRecordByToken(usertoken)
const character = await this.character.getCharacterByName(charactername)
@@ -131,30 +133,62 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
const currency = await this.userManager.getCurrency(record.user)
if(currency < 1) return
const existingToken = await this.getToken(character, item)
const shadowTokens = await this.getTokens(character, false)
const activeTokens = await this.getTokens(character, true)
await this.userManager.decrementCurrency(record.user, 1)
const modifier = await this.calculatePriorities(itemname, character)
if(!existingToken){
const modifier = await this.calculatePriorities(itemname, character)
await this.admin.knex('tokens').insert({
characterid: character.id,
itemid: item.id,
level: 1+modifier
})
}else{
await this.admin.knex('tokens').where({
characterid: character.id,
itemid: item.id
}).increment('level')
//tokens with deleted signups
if(shadowTokens.length > 0){
//token for current item
const matchingtoken = shadowTokens.find(token => token.itemname === itemname)
if(matchingtoken){
//update signupid and increment level
console.log("delete shadow tokens");
await this.admin
.knex('tokens')
.update({
signupid: signup.id,
level: matchingtoken.level+1
})
.where({
characterid: character.id,
itemname: item.itemname
})
return await this.getToken(character, item)
}
}
const matchingtoken = activeTokens.find(token => token.itemname === itemname)
if(matchingtoken){
//power up token
await this.admin
.knex('tokens')
.increment('level')
.where({
signupid: signup.id,
characterid: character.id,
itemname: item.itemname
})
}else{
await this.admin
.knex('tokens')
.insert({
characterid: character.id,
itemname: item.itemname,
level: 1+modifier,
signupid: signup.id
})
}
return await this.getToken(character, item)
}
getAllPriorities = async() :Promise<(SRPriority & Spec & Item)[]> => this.admin
.knex('priorities as p')
.join('items as i', 'p.itemid', '=', 'i.id')
.join('items as i', 'p.itemname', '=', 'i.itemname')
.leftJoin('specs as s', 'p.specid', '=', 's.id')
.select('*')
@@ -170,24 +204,24 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
await this.admin
.knex('priorities')
.insert(<SRPriority>{
itemid: item.id,
itemname: item.itemname,
...priority
})
}
getPriorities = async(itemname:string) : Promise<SRPriority[]> => {
const item = await this.getItem(itemname)
return await this.admin.knex('priorities')
.where('itemid', '=', item.id)
return await this.admin
.knex('priorities as p')
.where('p.itemname', '=', itemname)
.select('*')
}
calculatePriorities = async (itemname: string, character:Character):Promise<number>=> {
const rules : SRPriority[] = await this.admin.knex('priorities as p')
const rules : SRPriority[] = await this.admin
.knex('priorities as p')
.select('*')
.join('items as i', 'i.id', '=', 'p.itemid')
.where('itemname', '=', itemname)
.join('items as i', 'i.itemname', '=', 'p.itemname')
.where('p.itemname', '=', itemname)
return rules.map(rule => {
if(rule.specid && rule.race){
@@ -219,28 +253,37 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
.knex('tokens as t')
.select('*')
.join('characters as c', 'c.id', '=', 't.characterid')
.join('items as i', 'i.id', '=', 't.itemid')
.join('items as i', 'i.itemname', '=', 't.itemname')
.where({
characterid: character.id,
itemid: item.id
"i.itemname": item.itemname
})
.first()
}
getTokens = async (character:Character) : Promise<(SRToken & Character & Item)[]> => {
getTokens = async (character:Character, valid=true) : Promise<(SRToken & Character & Item)[]> => {
return await this.admin
.knex('tokens as t')
.select('*')
.select('*')
.join('characters as c', 'c.id', '=', 't.characterid')
.join('items as i', 'i.id', '=', 't.itemid')
.join('items as i', 'i.itemname', '=', 't.itemname')
.where({
characterid: character.id,
})
.andWhere(function(){
if(valid){
this.whereNotNull('t.signupid')
}else{
this.whereNull('t.signupid')
}
})
}
countItems = async() :Promise<number> => {
const count = await this.admin.knex('items').count('*');
const count = await this.admin
.knex('items')
.count('*');
return <number>count[0]['count(*)']
}
@@ -249,20 +292,24 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
if(this.initialized) return
this.initialized = true
const allItems = [...T1, ...T2]
const itemTiers = allItems
const countCache = await this.countItems()
getLogger('ItemManager').debug('Checking items, got: ',countCache, 'expected: ', allItems.length)
if(countCache != allItems.length){
const items:Item[] = await Promise.all(allItems.map((i) => this.fetchItem(i)))
try{
await this.admin
.knex('items')
.insert(items)
}catch(e){
getLogger('ItemManager').debug("Skipping item insertion")
}
if(countCache != Object.values(itemTiers).flat().length){
await Promise.all(
Object.entries(itemTiers)
.map((kv) => Promise.all(
kv[1].map(i => this.fetchItem(i)
.then(item => this.admin
.knex('items')
.insert({
tier: kv[0],
...item
})
))
))
)
}
}
}
+2 -2
View File
@@ -1,11 +1,11 @@
import { Raid, Signup, Character, RaidData } from "../../Types/Types"
import { Raid, Signup, Character, RaidData, User, Spec } from "../../Types/Types"
export class IRaidManager{
getRaids: () => Promise<Raid[]>
createRaid: (raid:Raid) => Promise<any>
addSignup: (signup: Signup) => Promise<any>
removeSignup: (signup: Signup) => Promise<any>
getSignups: (raid:Raid) => Promise<Signup[]>
getSignups: (raid:Raid) => Promise<(Signup & Character & Spec & User)[]>
sign: (userToken: string, character:Character, raid:Raid, late:boolean) => Promise<any>
unsign: (userToken: string, character:Character, raid:Raid,) => Promise<any>
archiveRaid: (raid:Raid) => Promise<RaidData>
+45 -22
View File
@@ -1,11 +1,12 @@
import { Inject, Injectable } from "../../Injector/ServiceDecorator";
import { RaidManagerIfc, RaidManagerFeatureIfc } from "./RPCInterface";
import { FrontworkComponent } from "../../Types/FrontworkComponent";
import { TableDefiniton, Signup, Raid, Character, RaidData, Spec, SRToken, Item } from "../../Types/Types";
import { TableDefiniton, Signup, Raid, Character, RaidData, Spec, SRToken, Item, User } from "../../Types/Types";
import { IAdmin } from "../../Admin/Interface";
import { IRaidManager } from "./Interface";
import { IUserManager } from "../User/Interface";
import { ICharacterManager } from "../Character/Interface";
import { _Tiers } from "../../Types/Items";
@Injectable(IRaidManager)
export class RaidManager
@@ -59,6 +60,7 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
table.string('description').notNullable()
table.string('title').notNullable()
table.integer('size').defaultTo(40)
table.enu('tier', _Tiers).defaultTo(null as any)
}
},{
name: 'archive',
@@ -69,7 +71,8 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
},{
name: 'signups',
tableBuilder: (table) => {
table.primary(['raidid', 'characterid'])
table.increments('id').primary()
table.unique(['raidid', 'characterid'])
table.integer('raidid')
table.foreign('raidid').references('id').inTable('raids').onDelete('CASCADE')
table.integer('characterid')
@@ -95,7 +98,7 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
raid_id: signup.raidid,
character_id: signup.characterid
})
.delete()
.del()
getRaids = async () : Promise<Raid[]> => {
@@ -116,7 +119,6 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
startRaid = async (raid:Raid) : Promise<RaidData> => {
const archived = await this.archiveRaid(raid)
delete archived.participants.late
const giveCurrency = async (b: Character) => {
@@ -140,6 +142,15 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
raiddata: JSON.stringify(raidData)
})
await Promise.all(
Object.values(raidData.participants).flat().flatMap((signup) => this.admin
.knex('tokens')
.where({
characterid: signup.characterid,
signupid: null
})
.del()
))
await this.admin.knex('raids')
.where('id', '=', raid.id)
@@ -175,17 +186,17 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
getRaidData = async (raid:Raid) : Promise<RaidData> => {
const ret = {
participants:{
Druid: <(Character&Spec)[]>[],
Hunter: <(Character&Spec)[]>[],
Mage: <(Character&Spec)[]>[],
Paladin: <(Character&Spec)[]>[],
Priest: <(Character&Spec)[]>[],
Rogue: <(Character&Spec)[]>[],
Shaman: <(Character&Spec)[]>[],
Warlock: <(Character&Spec)[]>[],
Warrior: <(Character&Spec)[]>[],
late: <(Character&Spec)[]>[],
bench: <(Character&Spec)[]>[],
Druid: <(Signup&Character&Spec)[]>[],
Hunter: <(Signup&Character&Spec)[]>[],
Mage: <(Signup&Character&Spec)[]>[],
Paladin: <(Signup&Character&Spec)[]>[],
Priest: <(Signup&Character&Spec)[]>[],
Rogue: <(Signup&Character&Spec)[]>[],
Shaman: <(Signup&Character&Spec)[]>[],
Warlock: <(Signup&Character&Spec)[]>[],
Warrior: <(Signup&Character&Spec)[]>[],
late: <(Signup&Character&Spec)[]>[],
bench: <(Signup&Character&Spec)[]>[],
},
tokens:{}
}
@@ -205,9 +216,9 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
.where('id','=',raid.id)
.first()
const characterData: (Character & Spec & Signup)[] = await this.admin
const characterData: (Signup & Character & Spec)[] = await this.admin
.knex('signups as s')
.select('characterid as id', 'charactername', 'class', 'specname', 'race', 'userid', 'benched', 'late', 'raidid', 'characterid')
.select('s.id as id', 'charactername', 'class', 'specname', 'race', 'userid', 'benched', 'late', 'raidid', 'characterid')
.join('raids as r', 's.raidid','=','r.id')
.join('characters as c', 's.characterid','=','c.id')
.join('users as u', 'c.userid','=','u.id')
@@ -228,12 +239,15 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
const tokenData: (Character & SRToken & Item)[] = await this.admin
.knex('signups as s')
.select('*')
.select('*', 's.id as id')
.join('raids as r', 's.raidid','=','r.id')
.where('r.id','=',raid.id)
.andWhere(function(){
this.whereNotNull('t.signupid')
})
.join('characters as c', 's.characterid','=','c.id')
.join('tokens as t', 't.characterid','=','c.id')
.join('items as i', 'i.id','=','t.itemid')
.join('items as i', 'i.itemname','=','t.itemname')
tokenData.forEach(data => {
if(!ret.tokens[data.itemname])
@@ -246,12 +260,12 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
}
}
getSignups = async (raid:Raid) : Promise<Signup[]> => await this.admin
.knex('signups')
getSignups = async (raid:Raid) : Promise<(Signup & Character & Spec & User)[]> => await this.admin
.knex('signups as si')
.join('characters as c', 'c.id', '=', 'characterid')
.join('specs as s', 's.id', '=', 'specid')
.join('users as u', 'u.id', '=', 'userid')
.select('*')
.select('*','si.id as id')
.where('raidid', '=', raid.id!)
sign = async (usertoken:string, character:Character, raid:Raid, late:boolean) => {
@@ -286,6 +300,15 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
late: late
})
}
return await this.admin
.knex('signups')
.select('*')
.where({
raidid: raid.id!,
characterid: character.id!,
})
.first()
}
unsign = async (usertoken:string, character:Character, raid:Raid) => {
+1 -2
View File
@@ -118,14 +118,13 @@ implements FrontworkComponent<UserManagerIfc, UserManagerFeatureIfc>, IUserManag
initialize = async () => {
this.exporters = [this.guild, this.item, this.raid, this.character]
//set up permissions
getLogger('UserManager').debug('inserting permissions')
getLogger('UserManager').debug('setting up permissions')
await Promise.all(
[this, ...this.exporters].flatMap(exp => exp.exportRPCFeatures().map(async (feature) => {
try{
await this.admin.knex.insert({ rpcname: feature.name }).into('rpcpermissions')
}catch(e){
getLogger('UserManager').debug(feature.name);
}
})))
+16
View File
@@ -1,3 +1,6 @@
export type Tiers = "MC" | 'BWL' | 'ZG' | 'AQ20' | 'AQ40' | 'Naxx'
export const _Tiers = ["MC", 'BWL', 'ZG', 'AQ20', 'AQ40', 'Naxx']
export const T1 = [
"Robe of Volatile Power",
"Salamander Scale Pants",
@@ -133,3 +136,16 @@ export const T2:string[] = [
"Interlaced Shadow Jerkin",
"Ringo's Blizzard Boots"
]
export type AllItems = {
[tier in Tiers] : string[]
}
export const allItems : AllItems = {
MC: T1,
BWL: T2,
ZG:[],
AQ20: [],
AQ40: [],
Naxx: []
}
+10 -6
View File
@@ -6,6 +6,7 @@ import { CharacterManagerIfc, CharacterManagerFeatureIfc } from "../Components/C
import { ItemManagerFeatureIfc, ItemManagerIfc } from "../Components/Item/RPCInterface";
import { GuildManagerFeatureIfc, GuildManagerIfc } from "../Components/Guild/RPCInterface";
import { ShoutboxIfc } from "../Components/Shoutbox/RPCInterface";
import { Tiers } from "./Items";
export type FrontcraftIfc = RaidManagerIfc
& UserManagerIfc
@@ -49,10 +50,10 @@ export type RPCPermission = {
export type RaidData = Raid & {
participants: {
[clazz in Class] : (Character & Spec)[]
[clazz in Class] : (Signup & Character & Spec)[]
} & {
late: (Character & Spec)[]
bench: (Character & Spec)[]
late: (Signup & Character & Spec)[]
bench: (Signup & Character & Spec)[]
}
tokens: {
[itemname in string]: (Character & SRToken & Item)[]
@@ -60,8 +61,9 @@ export type RaidData = Raid & {
}
export type SRToken = {
signupid?:number
characterid: number,
itemid: number,
itemname: string,
level: number
}
@@ -69,18 +71,18 @@ export type SRPriority = {
id?:number
race?:Race
specid?:number,
itemid?:number,
itemname?:string,
description?:string,
modifier:number
}
export type Item = {
id?:number
itemname:string
iconname:string
url:string
quality:string
hidden:boolean
tier: Tiers
}
export type User = {
@@ -98,9 +100,11 @@ export type Raid = {
start: string
signupcount?: number
size: number
tier: Tiers
}
export type Signup = {
id?:number
raidid: number
characterid: number
benched: boolean
@@ -1,13 +1,25 @@
<nb-card
class = "col-12 col-xl-9"
status="control">
<nb-card-header [ngStyle]="{'color': color}" style="text-transform: capitalize;">
{{char.charactername}}
<nb-card-header style="text-transform: capitalize;">
<h4>
<a *ngIf="link === 'character'" [ngStyle]="{'color': color}" [routerLink]="'/frontcraft/character/'+char.charactername">
{{char.charactername}}
</a>
</h4>
<h3>
<span [ngStyle]="{'color': color}" *ngIf="link !== 'character'">
{{char.charactername}}
</span>
</h3>
</nb-card-header>
<nb-card-body>
{{char.race}}<br />
{{char.specname}} {{char.class}}<br />
Owned by <a [routerLink]="'/frontcraft/user/'+char.username"> {{char.username}} ({{char.rank}})</a>
<span *ngIf="link === 'owner'">
Owned by <a [routerLink]="'/frontcraft/user/'+char.username"> {{char.username}} ({{char.rank}})</a>
</span>
<br/><br />
<span *ngFor="let token of tokens">
[ {{token.level}} ]
@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, Input } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { ApiService as ApiService } from '../../services/login-api';
import { Spec, User, Character } from '../../../../../../backend/Types/Types';
@@ -10,6 +10,9 @@ import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
})
export class FrontcraftCharacterComponent implements OnInit{
@Input() name?: string
@Input() link?: "owner" | "character" = 'owner'
char : (Character & User & Spec) = {} as any
color : string
tokens
@@ -20,7 +23,9 @@ export class FrontcraftCharacterComponent implements OnInit{
){}
async ngOnInit(){
const param = this.route.snapshot.paramMap.get('name');
const param = this.name || this.route.snapshot.paramMap.get('name');
if(!param) return
this.api.get('CharacterManager')
.getCharacterByName(param)
.then((char) => {
@@ -6,9 +6,6 @@
</nb-card-body>
</nb-card>
<nb-card class="col-12 col-xl-9">
<nb-card-body>
<input type="text" nbInput [(ngModel)]="search" (change)="changeSearch()" placeholder="Search" fullWidth="true" />
@@ -32,11 +32,12 @@ import { FrontcraftRaidComponent } from './raid/raid.component';
import { FrontcraftArchiveComponent } from './raid/archive.component';
import { NbEvaIconsModule } from '@nebular/eva-icons';
import { FrontcraftCharacerpickerComponent } from './raid/characterpicker.component';
import { FrontcraftShopComponent, FrontcraftBuyTokenComponent } from './shop/shop.component';
import { FrontcraftShopComponent } from './shop/shop.component';
import { FrontcraftRulesComponent } from './rules/rules.component';
import { FrontcraftItemSelectComponent } from './shop/itemselector.component';
import { NgxEchartsModule } from 'ngx-echarts';
import { FrontcraftCharactersComponent } from './characters/characters.component';
import { FrontcraftBuyTokenComponent } from './shop/buytoken.component';
@NgModule({
@@ -67,14 +67,15 @@
</div>
</nb-card-body>
</nb-card>
</ng-container>
</div>
</nb-tab>
<nb-tab tabTitle="Shop">
<shop (onSelect)="itemSelect($event)"></shop>
</nb-tab>
<nb-tab tabTitle="Reserves">
<nb-list>
<nb-list-item *ngFor="let item of raid.tokens | keyvalue">
<a [ngStyle]="{'color':item.value[0].quality=='Epic'?'#a335ee':'#ff8000'}"
target="_blank"
[href]="item.value[0].url">
@@ -5,6 +5,7 @@ import { RaidData, Raid, Signup } from '../../../../../../backend/Types/Types';
import { NbWindowService, NbToastrService, NbDialogService } from '@nebular/theme';
import { FrontcraftCharacerpickerComponent } from './characterpicker.component';
import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
import { FrontcraftBuyTokenComponent } from '../shop/buytoken.component';
@Component({
selector: 'raid',
@@ -52,6 +53,15 @@ export class FrontcraftRaidComponent implements OnInit{
this.refresh()
}
itemSelect = async(item) => {
this.dialogService.open(FrontcraftBuyTokenComponent, {
context: {
item: item,
signup: this.mySignup
}
}).onClose.subscribe(() => this.refresh())
}
signup = async () => {
const signupFeature = this.api.get('signup')
if(!signupFeature) return
@@ -60,7 +70,7 @@ export class FrontcraftRaidComponent implements OnInit{
closeOnBackdropClick: true,
closeOnEsc: true,
context: {
'raid': this.raid,
raid: this.raid,
}
}).onClose.subscribe(()=>{
this.refresh()
@@ -83,7 +93,7 @@ export class FrontcraftRaidComponent implements OnInit{
const signupFeature = this.api.get('signup')
if(!signupFeature) return
await signupFeature.unsign(this.api.getAuth().token.value, this.mySignup, this.raid)
await signupFeature.unsign(this.api.getAuth().token.value, <any>{id: this.mySignup.characterid, userid: this.mySignup.userid}, this.raid)
this.toast.show('Success', 'Unsigned', { status: 'success' })
this.refresh()
}
@@ -103,6 +113,7 @@ export class FrontcraftRaidComponent implements OnInit{
const user = this.api.getCurrentUser()
const matchingSignup = Object.values(raiddata.participants).flat().find(char => user && char.userid === user.id!)
if(matchingSignup){
this.isSignedup = true
this.mySignup = matchingSignup
this.mySignup.status = matchingSignup['benched']?'Bench':matchingSignup['late']?'Late':'Attending'
@@ -4,7 +4,7 @@
<nb-tab tabTitle="Info">
Smart text here
</nb-tab>
<nb-tab *ngIf="managePriorities" tabTitle="priorities">
<nb-tab tabTitle="priorities">
<nb-list>
<nb-list-item *ngFor="let item of rules | keyvalue">
<a [ngStyle]="{'color':item.value[0].quality=='Epic'?'#a335ee':'#ff8000'}"
@@ -0,0 +1,104 @@
import { Component, OnInit, ContentChild, AfterContentInit, ViewChild, AfterViewInit, Input, Output, EventEmitter } from '@angular/core';
import { ApiService as ApiService } from '../../services/login-api';
import { FrontcraftItemSelectComponent } from './itemselector.component';
import { NbWindowService, NbWindowRef, NbToastrService, NbDialogService, NbDialogRef } from '@nebular/theme';
import { Item, Character, SRToken, Signup } from '../../../../../../backend/Types/Types';
import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
import { _Tiers, allItems, Tiers } from '../../../../../../backend/Types/Items';
@Component({
selector: 'buyToken',
template: `
<nb-card class="col-12 col-xl-9">
<nb-card-header>
Buy {{item.itemname}}
</nb-card-header>
<nb-card-body>
<p>
You currently have {{currency}} softreserve currency
</p>
<div *ngIf="currency>0">
<div *ngFor="let kv of modifier | keyvalue">
<button
(click)="buyToken(kv.key)"
[disabled]="currency<=0"
nbButton
outline
status="success"
size="tiny">
buy
</button>
{{kv.key}} <span *ngIf="kv.value>0">(<b>+{{kv.value}}</b> from priorities)</span>
</div>
<div *ngFor="let token of ownedtokens">
<button
(click)="buyToken(token.charactername)"
nbButton
outline
status="success"
size="tiny">
buy
</button>
{{token.charactername}} [ {{token.level}} ] => [ {{token.level+1}} ]
</div>
</div>
</nb-card-body>
</nb-card>
`,
})
export class FrontcraftBuyTokenComponent implements OnInit{
@Input() item : Item
@Input() signup : Signup
@Input() tier: Tiers
characters: Character[]
modifier = {}
currency: number = 0
ownedtokens: SRToken[] = []
constructor(
private toastr: NbToastrService,
protected dialogRef: NbDialogRef<FrontcraftBuyTokenComponent>,
private api : ApiService
){}
ngOnInit(): void {
const usr = this.api.getCurrentUser()
this.api.get('CharacterManager')
.getCharactersOfUser(usr.username)
.then(chars => {
chars.forEach(char => {
char['color'] = getClassColor(char.class)
this.api.get('ItemManager').getToken(char, this.item).then(token => {
if(token) this.ownedtokens.push(token)
else{
this.api.get('ItemManager').calculatePriorities(this.item.itemname, char).then(modifier => {
this.modifier[char.charactername] = modifier
})
}
})
})
this.characters = chars
})
this.api.get('UserManager').getUser(usr.username).then(u => {
if(!u) return
this.currency = u.currency
})
}
buyToken = async (charactername:string) => {
const src = this.api.get('ItemManager')
const token = await src.buyToken(this.api.getAuth().token.value, charactername, this.item.itemname, this.signup)
if(token){
this.toastr.show(token.characterid+' now has a token for '+token.itemname+' of level '+token.level, 'Yay', {status: 'success'})
}else{
this.toastr.show('Error (something went wrong)', 'Oh no', {status: 'danger'})
}
this.dialogRef.close()
}
}
@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { ApiService } from '../../services/login-api';
import { Item } from '../../../../../../backend/Types/Types';
@@ -10,10 +10,11 @@ export class FrontcraftItemSelectComponent implements OnInit{
selected: Item
search: string
items: any[]
allItems:Item[] = []
displayedItems: any[]
callbacks = []
@Input() items: string[]
@Output() onSelect = new EventEmitter<Item>();
constructor(
private api: ApiService,
@@ -21,25 +22,23 @@ export class FrontcraftItemSelectComponent implements OnInit{
}
async ngOnInit(){
this.api.get('ItemManager').getItems().then(items => {
this.items = items
this.displayedItems = items
Promise.all(this.items.map(itemname =>
this.api.get('ItemManager').getItem(itemname)
)).then(items => {
this.allItems = items
this.displayedItems = this.allItems
})
}
changeSearch(){
if(!this.search || this.search == "")
this.displayedItems = this.items
this.displayedItems = this.allItems
else
this.displayedItems = this.items.filter(it => it.itemname.toLowerCase().includes(this.search.toLowerCase()))
this.displayedItems = this.allItems.filter(it => it.itemname.toLowerCase().includes(this.search.toLowerCase()))
}
select(item: Item){
this.selected = item
this.callbacks.forEach(cb => cb(item))
this.onSelect.emit(item)
}
onselect(callback:Function){
this.callbacks.push(callback)
}
}
@@ -1,13 +1,7 @@
<h3>
{{tier}} items
</h3>
<nb-card class="col-12 col-xl-9">
<nb-card-body>
<nb-tabset>
<nb-tab tabTitle="Items">
<itemselect></itemselect>
</nb-tab>
<nb-tab tabTitle="About">
</nb-tab>
</nb-tabset>
</nb-card-body>
</nb-card>
<itemselect
[items]="allItems[tier]"
(onSelect)="onSelect.emit($event)"></itemselect>
@@ -1,43 +1,28 @@
import { Component, OnInit, ContentChild, AfterContentInit, ViewChild, AfterViewInit } from '@angular/core';
import { Component, OnInit, ContentChild, AfterContentInit, ViewChild, AfterViewInit, Input, Output, EventEmitter } from '@angular/core';
import { ApiService as ApiService } from '../../services/login-api';
import { FrontcraftItemSelectComponent } from './itemselector.component';
import { NbWindowService, NbWindowRef, NbToastrService, NbDialogService, NbDialogRef } from '@nebular/theme';
import { Item, Character, SRToken } from '../../../../../../backend/Types/Types';
import { Item, Character, SRToken, Signup } from '../../../../../../backend/Types/Types';
import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
import { _Tiers, allItems } from '../../../../../../backend/Types/Items';
@Component({
selector: 'shop',
templateUrl: './shop.component.html',
})
export class FrontcraftShopComponent implements AfterViewInit{
export class FrontcraftShopComponent{
@ViewChild(FrontcraftItemSelectComponent, {static: false})
itemselect !: FrontcraftItemSelectComponent
@Input() character: Character
@Input() signup: Signup
@Input() tier = _Tiers[0]
@Output() onSelect = new EventEmitter<Item>()
allItems = allItems
constructor(
private api: ApiService,
private dialogService : NbDialogService
){
window['shop'] = this
}
buy = (item) => {
this.dialogService.open(FrontcraftBuyTokenComponent, {
closeOnBackdropClick: true,
closeOnEsc: true,
context: {
item: item
}
}).onClose.subscribe(()=>{
});
}
ngAfterViewInit(){
this.itemselect.onselect(this.buy)
}
){}
}
@Component({
@@ -7,32 +7,8 @@ accent="info">
</nb-card-header>
<nb-card-body>
{{user.currency}}
<nb-card
accent="control"
*ngFor="let char of characters">
<nb-card-header>
<h4>
<a [ngStyle]="{'color': char.color}" style="text-transform: capitalize;" [routerLink]="'/frontcraft/character/'+char.charactername">
{{char.charactername}}
</a>
</h4>
</nb-card-header>
<nb-card-body>
{{char.race}}<br />
{{char.specname}} {{char.class}}
<br />
<br />
<span *ngFor="let token of char.tokens">
[ {{token.level}} ]
<a [ngStyle]="{'color':token.quality=='Epic'?'#a335ee':'#ff8000'}"
target="_blank"
[href]="token.url">
<img style="min-width: 25px; width: 2.25vw; max-width: 50px"
[src]="'https://wow.zamimg.com/images/wow/icons/large/'+token.iconname+'.jpg'" />
{{token.itemname}}
</a><br />
</span>
</nb-card-body>
</nb-card>
<ng-container *ngFor="let char of characters">
<character [name]="char.charactername" [link]="'character'"></character>
</ng-container>
</nb-card-body>
</nb-card>
@@ -134,14 +134,6 @@ export class ApiService{
}
}
function str2arraybuf(str:string): ArrayBuffer {
return new Buffer(str)
}
function buf2hex(buffer: ArrayBuffer) {
return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
}
export async function hash(value:string) : Promise<string>{
return saltedHash(value, "")
}
+22 -12
View File
@@ -3,7 +3,7 @@ import { FrontworkAdmin } from "../src/backend/Admin/Admin";
import { T1 } from "../src/backend/Types/Items";
import { RPCSocket } from "rpclibrary";
import { FrontcraftIfc, Auth, User, FrontcraftFeatureIfc, Raid, Character, Rank, Class, Race, SRPriority, Spec } from "../src/backend/Types/Types";
import { FrontcraftIfc, Auth, User, FrontcraftFeatureIfc, Raid, Character, Rank, Class, Race, SRPriority, Spec, Signup } from "../src/backend/Types/Types";
import { SpecT } from "../src/backend/Types/PlayerSpecs";
@@ -107,7 +107,7 @@ describe('Frontcraft', () => {
client : RPCSocket & FrontcraftIfc,
adminClient : RPCSocket & FrontcraftFeatureIfc,
raids: Raid[] = [],
users : {[username in string] : { account: User, character: Character, auth: Auth, item?:string }} = {}
users : {[username in string] : { account: User, character: Character, auth: Auth, signup?:Signup, item?:string }} = {}
const createAccount = (user: User) => {
return client.UserManager.createUser(user)
@@ -217,9 +217,12 @@ describe('Frontcraft', () => {
adminClient.signup.sign(user.auth.token.value, user.character, raids[0], false).catch(done)
)).then(x => {
adminClient.signup.getSignups(raids[0]).then(s => {
if(s.length == testAccounts.length)
if(s.length == testAccounts.length){
s.forEach(sign => {
users[sign.username].signup = sign
})
done()
else{
}else{
done("Unexpected number of signups: "+s.length)
}
})
@@ -467,7 +470,7 @@ describe('Frontcraft', () => {
const itemname = T1[0]//T1[Math.floor(T1.length*Math.random())]
const modifier = await client.ItemManager.calculatePriorities(itemname, user.character)
const token = await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname)
const token = await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, user.signup!)
users[user.account.username].item = itemname
if(!token) return false
@@ -480,7 +483,7 @@ describe('Frontcraft', () => {
it('not buy token without currency', (done)=>{
const user = Object.values(users)[0]
const itemname = T1[0]
client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname).then(token => {
client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, user.signup!).then(token => {
if(!token)
done()
else {
@@ -497,12 +500,18 @@ describe('Frontcraft', () => {
const item = await client.ItemManager.getItem(itemname)
const before = await client.ItemManager.getToken(user.character, item)
if(!before || before.level !== 7) return
if(!before || before.level !== 7) {
console.log("expected level to be 7", before);
return
}
await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname)
const after = await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname)
await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, user.signup!)
const after = await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, user.signup!)
if(!after || after.level !== 9) return
if(!after || after.level !== 9) {
console.log("expected level to be 9", after);
return
}
done()
})
})
@@ -510,11 +519,12 @@ describe('Frontcraft', () => {
it('should buy more tokens', (done) => {
Promise.all(Object.values(users).map(async (user) => {
await adminClient.softreserveCurrency.incrementCurrency(user.account, 1)
await client.ItemManager
return await client.ItemManager
.buyToken(
user.auth.token.value,
user.character.charactername,
T1[Math.floor(T1.length*Math.random())]
T1[Math.floor(T1.length*Math.random())],
user.signup!
)
})).then(_ => {
done()