@@ -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,14 +87,14 @@ 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
79
92
const date24HoursAgo = new Date ( Date . now ( ) - 24 * 60 * 60 * 1000 ) ;
80
93
const depositHistory = await this . fetchBankHistory ( date24HoursAgo ) ;
81
94
82
95
const authedPlayerObject : AuthedPlayerObject = Object . assign ( playerObject , {
83
96
attackStrength : attackStrength ,
84
- defenceStrength : defenceStrength ,
97
+ defenseStrength : defenseStrength ,
85
98
attackTurns : this . attackTurns ,
86
99
experience : this . experience ,
87
100
goldInBank : this . goldInBank ,
@@ -96,6 +109,8 @@ export default class PlayerModel {
96
109
quantity : unit . quantity ,
97
110
} ) ) ,
98
111
structureUpgrades : this . structureUpgrades ,
112
+ proficiencyPoints : this . proficiencyPoints ,
113
+ remainingProficiencyPoints : this . proficiencyPointsRemaining ,
99
114
} ) ;
100
115
101
116
return authedPlayerObject ;
@@ -151,13 +166,48 @@ export default class PlayerModel {
151
166
return fortificationUpgrades [ this . structureUpgrades . fortification ] ;
152
167
}
153
168
169
+ get proficiencyPointsTotal ( ) : number {
170
+ return Object . values ( this . proficiencyPoints ) . reduce (
171
+ ( acc , points ) => acc + points ,
172
+ 0 ,
173
+ ) ;
174
+ }
175
+
176
+ get proficiencyPointsRemaining ( ) : number {
177
+ // The player gets 1 proficiency point per level
178
+ // Since the player starts at level 1, we subtract 1 from the level
179
+ return this . level - 1 - this . proficiencyPointsTotal ;
180
+ }
181
+
182
+ async upgradeProficiencyPoints ( points : {
183
+ strength : number ;
184
+ constitution : number ;
185
+ wealth : number ;
186
+ dexterity : number ;
187
+ charisma : number ;
188
+ } ) {
189
+ this . ctx . logger . debug ( { points } , 'Upgrading proficiency points' ) ;
190
+ const totalPoints = Object . values ( points ) . reduce (
191
+ ( acc , point ) => acc + point ,
192
+ 0 ,
193
+ ) ;
194
+
195
+ if ( totalPoints > this . proficiencyPointsRemaining ) {
196
+ throw new Error ( 'Not enough proficiency points' ) ;
197
+ }
198
+
199
+ this . proficiencyPoints = points ;
200
+ await this . save ( ) ;
201
+ }
202
+
154
203
async upgradeStructure (
155
204
type : keyof typeof structureUpgrades ,
156
205
desiredUpgrade : StructureUpgrade ,
157
206
) {
158
207
this . ctx . logger . debug ( { type } , 'Upgrading structure' ) ;
159
-
160
- this . gold -= desiredUpgrade . cost ;
208
+ const bonus = getCostModifier ( this ) ;
209
+ const cost = applyBonuses ( false , desiredUpgrade . cost , bonus ) ;
210
+ this . gold -= Math . floor ( cost ) ;
161
211
this . structureUpgrades [ type ] += 1 ;
162
212
163
213
this . save ( ) ;
@@ -168,47 +218,29 @@ export default class PlayerModel {
168
218
( acc , unit ) => acc + unit . calculateAttackStrength ( ) ,
169
219
0 ,
170
220
) ;
171
- if ( this . race === 'human' || this . race === 'undead' ) {
172
- // Humans and Undead get a 5% bonus to attack strength
173
- offense *= 1.05 ;
174
- }
175
- if ( this . class === 'fighter' ) {
176
- // Fighters get a 5% bonus to attack strength
177
- offense *= 1.05 ;
178
- }
221
+ const bonus = getAttackModifier ( this ) ;
222
+ offense = applyBonuses ( true , offense , bonus ) ;
179
223
return Math . floor ( offense ) ;
180
224
}
181
225
182
- async calculateDefenceStrength ( ) : Promise < number > {
183
- let defence = this . units . reduce (
184
- ( acc , unit ) => acc + unit . calculateDefenceStrength ( ) ,
226
+ async calculateDefenseStrength ( ) : Promise < number > {
227
+ let defense = this . units . reduce (
228
+ ( acc , unit ) => acc + unit . calculateDefenseStrength ( ) ,
185
229
0 ,
186
230
) ;
187
- if ( this . race === 'elf' || this . race === 'goblin' ) {
188
- // Elves and Goblins get a 5% bonus to defence strength
189
- defence *= 1.05 ;
190
- }
191
- if ( this . class === 'cleric' ) {
192
- // Clerics get a 5% bonus to defence strength
193
- defence *= 1.05 ;
194
- }
195
-
196
- const fortificationBonus = this . fortification . defenceBonusPercentage ;
197
- defence *= 1 + fortificationBonus / 100 ;
198
-
199
- return Math . floor ( defence ) ;
231
+ const bonus = getDefenseModifier ( this ) ;
232
+ defense = applyBonuses ( true , defense , bonus ) ;
233
+ return Math . floor ( defense ) ;
200
234
}
201
235
202
236
async calculateGoldPerTurn ( ) : Promise < number > {
203
237
let goldPerTurn = this . units . reduce (
204
238
( acc , unit ) => acc + unit . calculateGoldPerTurn ( ) ,
205
239
0 ,
206
240
) ;
207
- if ( this . class === 'thief' ) {
208
- // Thieves get a 5% bonus to gold per turn
209
- goldPerTurn *= 1.05 ;
210
- }
211
241
242
+ const bonus = getIncomeModifier ( this ) ;
243
+ goldPerTurn = applyBonuses ( true , goldPerTurn , bonus ) ;
212
244
const fortificationGoldPerTurn = this . fortification . goldPerTurn ;
213
245
goldPerTurn += fortificationGoldPerTurn ;
214
246
@@ -233,12 +265,12 @@ export default class PlayerModel {
233
265
const warHistoryID = `WRH-${ ulid ( ) } ` ;
234
266
235
267
const playerAttackStrength = await this . calculateAttackStrength ( ) ;
236
- const targetPlayerDefenceStrength =
237
- await targetPlayer . calculateDefenceStrength ( ) ;
268
+ const targetPlayerDefenseStrength =
269
+ await targetPlayer . calculateDefenseStrength ( ) ;
238
270
239
271
const isVictor = this . determineIsVictor (
240
272
playerAttackStrength ,
241
- targetPlayerDefenceStrength ,
273
+ targetPlayerDefenseStrength ,
242
274
) ;
243
275
244
276
// Calculate XP
@@ -259,7 +291,7 @@ export default class PlayerModel {
259
291
attack_turns_used : attackTurns ,
260
292
is_attacker_victor : false ,
261
293
attacker_strength : playerAttackStrength ,
262
- defender_strength : targetPlayerDefenceStrength ,
294
+ defender_strength : targetPlayerDefenseStrength ,
263
295
gold_stolen : 0 ,
264
296
created_at : new Date ( ) ,
265
297
attacker_experience : 0 ,
@@ -291,7 +323,7 @@ export default class PlayerModel {
291
323
attack_turns_used : attackTurns ,
292
324
is_attacker_victor : true ,
293
325
attacker_strength : playerAttackStrength ,
294
- defender_strength : targetPlayerDefenceStrength ,
326
+ defender_strength : targetPlayerDefenseStrength ,
295
327
gold_stolen : winnings ,
296
328
created_at : new Date ( ) ,
297
329
attacker_experience : victorExperience ,
@@ -311,6 +343,7 @@ export default class PlayerModel {
311
343
experience : this . experience ,
312
344
overall_rank : this . overallRank ,
313
345
structureUpgrades : this . structureUpgrades ,
346
+ proficiencyPoints : this . proficiencyPoints ,
314
347
} ,
315
348
) ;
316
349
@@ -335,6 +368,13 @@ export default class PlayerModel {
335
368
fortification : row . structureUpgrades ?. fortification || 0 ,
336
369
housing : row . structureUpgrades ?. housing || 0 ,
337
370
} ;
371
+ this . proficiencyPoints = {
372
+ strength : row . proficiencyPoints ?. strength || 0 ,
373
+ constitution : row . proficiencyPoints ?. constitution || 0 ,
374
+ wealth : row . proficiencyPoints ?. wealth || 0 ,
375
+ dexterity : row . proficiencyPoints ?. dexterity || 0 ,
376
+ charisma : row . proficiencyPoints ?. charisma || 0 ,
377
+ } ;
338
378
}
339
379
340
380
static async fetchAllForUser ( ctx : Context , user : UserModel ) {
0 commit comments