@@ -23,6 +23,13 @@ import {
23
23
} from '@darkthrone/game-data' ;
24
24
import { getRandomNumber } from '../utils' ;
25
25
import { Paginator } from '../lib/paginator' ;
26
+ import {
27
+ getAttackModifier ,
28
+ getDefenseModifier ,
29
+ getIncomeModifier ,
30
+ getCostModifier ,
31
+ applyBonuses ,
32
+ } from '../lib/bonusHelper' ;
26
33
27
34
export default class PlayerModel {
28
35
private ctx : Context ;
@@ -44,14 +51,20 @@ export default class PlayerModel {
44
51
fortification : number ;
45
52
housing : number ;
46
53
} ;
54
+ public proficiencyPoints : {
55
+ strength : number ;
56
+ constitution : number ;
57
+ wealth : number ;
58
+ dexterity : number ;
59
+ charisma : number ;
60
+ } ;
47
61
48
62
public units : PlayerUnitsModel [ ] ;
49
63
50
64
constructor ( ctx : Context , data : PlayerRow , units : PlayerUnitsModel [ ] ) {
51
65
this . ctx = ctx ;
52
-
53
- this . populateFromRow ( data ) ;
54
66
this . units = units ;
67
+ this . populateFromRow ( data ) ;
55
68
}
56
69
57
70
async serialise ( ) : Promise < PlayerObject | AuthedPlayerObject > {
@@ -74,15 +87,15 @@ export default class PlayerModel {
74
87
if ( ! isAuthed ) return playerObject ;
75
88
76
89
const attackStrength = await this . calculateAttackStrength ( ) ;
77
- const defenceStrength = await this . calculateDefenceStrength ( ) ;
90
+ const defenseStrength = await this . calculateDefenseStrength ( ) ;
78
91
const goldPerTurn = await this . calculateGoldPerTurn ( ) ;
79
92
80
93
const date24HoursAgo = new Date ( Date . now ( ) - 24 * 60 * 60 * 1000 ) ;
81
94
const depositHistory = await this . fetchBankHistory ( date24HoursAgo ) ;
82
95
83
96
const authedPlayerObject : AuthedPlayerObject = Object . assign ( playerObject , {
84
97
attackStrength : attackStrength ,
85
- defenceStrength : defenceStrength ,
98
+ defenseStrength : defenseStrength ,
86
99
attackTurns : this . attackTurns ,
87
100
experience : this . experience ,
88
101
goldInBank : this . goldInBank ,
@@ -98,6 +111,8 @@ export default class PlayerModel {
98
111
quantity : unit . quantity ,
99
112
} ) ) ,
100
113
structureUpgrades : this . structureUpgrades ,
114
+ proficiencyPoints : this . proficiencyPoints ,
115
+ remainingProficiencyPoints : this . proficiencyPointsRemaining ,
101
116
} ) ;
102
117
103
118
return authedPlayerObject ;
@@ -153,13 +168,48 @@ export default class PlayerModel {
153
168
return fortificationUpgrades [ this . structureUpgrades . fortification ] ;
154
169
}
155
170
171
+ get proficiencyPointsTotal ( ) : number {
172
+ return Object . values ( this . proficiencyPoints ) . reduce (
173
+ ( acc , points ) => acc + points ,
174
+ 0 ,
175
+ ) ;
176
+ }
177
+
178
+ get proficiencyPointsRemaining ( ) : number {
179
+ // The player gets 1 proficiency point per level
180
+ // Since the player starts at level 1, we subtract 1 from the level
181
+ return this . level - 1 - this . proficiencyPointsTotal ;
182
+ }
183
+
184
+ async upgradeProficiencyPoints ( points : {
185
+ strength : number ;
186
+ constitution : number ;
187
+ wealth : number ;
188
+ dexterity : number ;
189
+ charisma : number ;
190
+ } ) {
191
+ this . ctx . logger . debug ( { points } , 'Upgrading proficiency points' ) ;
192
+ const totalPoints = Object . values ( points ) . reduce (
193
+ ( acc , point ) => acc + point ,
194
+ 0 ,
195
+ ) ;
196
+
197
+ if ( totalPoints > this . proficiencyPointsRemaining ) {
198
+ throw new Error ( 'Not enough proficiency points' ) ;
199
+ }
200
+
201
+ this . proficiencyPoints = points ;
202
+ await this . save ( ) ;
203
+ }
204
+
156
205
async upgradeStructure (
157
206
type : keyof typeof structureUpgrades ,
158
207
desiredUpgrade : StructureUpgrade ,
159
208
) {
160
209
this . ctx . logger . debug ( { type } , 'Upgrading structure' ) ;
161
-
162
- this . gold -= desiredUpgrade . cost ;
210
+ const bonus = getCostModifier ( this ) ;
211
+ const cost = applyBonuses ( false , desiredUpgrade . cost , bonus ) ;
212
+ this . gold -= Math . floor ( cost ) ;
163
213
this . structureUpgrades [ type ] += 1 ;
164
214
165
215
this . save ( ) ;
@@ -170,47 +220,29 @@ export default class PlayerModel {
170
220
( acc , unit ) => acc + unit . calculateAttackStrength ( ) ,
171
221
0 ,
172
222
) ;
173
- if ( this . race === 'human' || this . race === 'undead' ) {
174
- // Humans and Undead get a 5% bonus to attack strength
175
- offense *= 1.05 ;
176
- }
177
- if ( this . class === 'fighter' ) {
178
- // Fighters get a 5% bonus to attack strength
179
- offense *= 1.05 ;
180
- }
223
+ const bonus = getAttackModifier ( this ) ;
224
+ offense = applyBonuses ( true , offense , bonus ) ;
181
225
return Math . floor ( offense ) ;
182
226
}
183
227
184
- async calculateDefenceStrength ( ) : Promise < number > {
185
- let defence = this . units . reduce (
186
- ( acc , unit ) => acc + unit . calculateDefenceStrength ( ) ,
228
+ async calculateDefenseStrength ( ) : Promise < number > {
229
+ let defense = this . units . reduce (
230
+ ( acc , unit ) => acc + unit . calculateDefenseStrength ( ) ,
187
231
0 ,
188
232
) ;
189
- if ( this . race === 'elf' || this . race === 'goblin' ) {
190
- // Elves and Goblins get a 5% bonus to defence strength
191
- defence *= 1.05 ;
192
- }
193
- if ( this . class === 'cleric' ) {
194
- // Clerics get a 5% bonus to defence strength
195
- defence *= 1.05 ;
196
- }
197
-
198
- const fortificationBonus = this . fortification . defenceBonusPercentage ;
199
- defence *= 1 + fortificationBonus / 100 ;
200
-
201
- return Math . floor ( defence ) ;
233
+ const bonus = getDefenseModifier ( this ) ;
234
+ defense = applyBonuses ( true , defense , bonus ) ;
235
+ return Math . floor ( defense ) ;
202
236
}
203
237
204
238
async calculateGoldPerTurn ( ) : Promise < number > {
205
239
let goldPerTurn = this . units . reduce (
206
240
( acc , unit ) => acc + unit . calculateGoldPerTurn ( ) ,
207
241
0 ,
208
242
) ;
209
- if ( this . class === 'thief' ) {
210
- // Thieves get a 5% bonus to gold per turn
211
- goldPerTurn *= 1.05 ;
212
- }
213
243
244
+ const bonus = getIncomeModifier ( this ) ;
245
+ goldPerTurn = applyBonuses ( true , goldPerTurn , bonus ) ;
214
246
const fortificationGoldPerTurn = this . fortification . goldPerTurn ;
215
247
goldPerTurn += fortificationGoldPerTurn ;
216
248
@@ -235,12 +267,12 @@ export default class PlayerModel {
235
267
const warHistoryID = `WRH-${ ulid ( ) } ` ;
236
268
237
269
const playerAttackStrength = await this . calculateAttackStrength ( ) ;
238
- const targetPlayerDefenceStrength =
239
- await targetPlayer . calculateDefenceStrength ( ) ;
270
+ const targetPlayerDefenseStrength =
271
+ await targetPlayer . calculateDefenseStrength ( ) ;
240
272
241
273
const isVictor = this . determineIsVictor (
242
274
playerAttackStrength ,
243
- targetPlayerDefenceStrength ,
275
+ targetPlayerDefenseStrength ,
244
276
) ;
245
277
246
278
// Calculate XP
@@ -261,7 +293,7 @@ export default class PlayerModel {
261
293
attack_turns_used : attackTurns ,
262
294
is_attacker_victor : false ,
263
295
attacker_strength : playerAttackStrength ,
264
- defender_strength : targetPlayerDefenceStrength ,
296
+ defender_strength : targetPlayerDefenseStrength ,
265
297
gold_stolen : 0 ,
266
298
created_at : new Date ( ) ,
267
299
attacker_experience : 0 ,
@@ -293,7 +325,7 @@ export default class PlayerModel {
293
325
attack_turns_used : attackTurns ,
294
326
is_attacker_victor : true ,
295
327
attacker_strength : playerAttackStrength ,
296
- defender_strength : targetPlayerDefenceStrength ,
328
+ defender_strength : targetPlayerDefenseStrength ,
297
329
gold_stolen : winnings ,
298
330
created_at : new Date ( ) ,
299
331
attacker_experience : victorExperience ,
@@ -313,6 +345,7 @@ export default class PlayerModel {
313
345
experience : this . experience ,
314
346
overall_rank : this . overallRank ,
315
347
structureUpgrades : this . structureUpgrades ,
348
+ proficiencyPoints : this . proficiencyPoints ,
316
349
} ,
317
350
) ;
318
351
@@ -337,6 +370,13 @@ export default class PlayerModel {
337
370
fortification : row . structureUpgrades ?. fortification || 0 ,
338
371
housing : row . structureUpgrades ?. housing || 0 ,
339
372
} ;
373
+ this . proficiencyPoints = {
374
+ strength : row . proficiencyPoints ?. strength || 0 ,
375
+ constitution : row . proficiencyPoints ?. constitution || 0 ,
376
+ wealth : row . proficiencyPoints ?. wealth || 0 ,
377
+ dexterity : row . proficiencyPoints ?. dexterity || 0 ,
378
+ charisma : row . proficiencyPoints ?. charisma || 0 ,
379
+ } ;
340
380
}
341
381
342
382
static async fetchAllForUser ( ctx : Context , user : UserModel ) {
0 commit comments