survivors: split between base stats, temp stats and effective stats for players

changed the way how stats are increased/decreased
This commit is contained in:
Sheldan
2025-09-09 22:39:14 +02:00
parent 28ef7b9c6f
commit fa477afb9a
7 changed files with 82 additions and 39 deletions

View File

@@ -4,7 +4,9 @@ import {fillDot, getCoordinatesSplit} from "./utils.ts";
export class Player implements Drawable, Acting, Healthy { export class Player implements Drawable, Acting, Healthy {
private _position: Vector; private _position: Vector;
private _stats: PlayerStats; private _baseStats: PlayerStats;
private _effectiveStats: PlayerStats;
private _tempStats: PlayerStats;
private _color: string; private _color: string;
private _status: PlayerStatus; private _status: PlayerStatus;
@@ -20,7 +22,7 @@ export class Player implements Drawable, Acting, Healthy {
} }
draw(ctx: CanvasRenderingContext2D) { draw(ctx: CanvasRenderingContext2D) {
fillDot(this.position, this._stats.size, this._color, ctx) fillDot(this.position, this._effectiveStats.size, this._color, ctx)
this._weapons.forEach(weapon => weapon.draw(ctx)) this._weapons.forEach(weapon => weapon.draw(ctx))
} }
@@ -30,7 +32,10 @@ export class Player implements Drawable, Acting, Healthy {
} }
let player = new Player(position); let player = new Player(position);
player._color = 'blue'; player._color = 'blue';
player._stats = PlayerStats.defaultPlayerStats(); player._baseStats = PlayerStats.defaultPlayerStats();
let tempStats = new PlayerStats();
tempStats.resetToBasic()
player._tempStats = tempStats;
player._speed = new Vector(0, 0) player._speed = new Vector(0, 0)
player._status = new PlayerStatus(10, 0, 0); player._status = new PlayerStatus(10, 0, 0);
return player; return player;
@@ -60,9 +65,15 @@ export class Player implements Drawable, Acting, Healthy {
this._status.health -= damage; this._status.health -= damage;
} }
statsChanged() {
this._effectiveStats.resetToBasic()
this._effectiveStats.mergeStats(this._baseStats)
this._effectiveStats.mergeStats(this._tempStats)
}
heal(amount: number) { heal(amount: number) {
this._status.health += amount; this._status.health += amount;
this._status.health = Math.min(this._status.health, this._stats.health) this._status.health = Math.min(this._status.health, this._effectiveStats.health)
} }
get health(): number { get health(): number {
@@ -77,8 +88,8 @@ export class Player implements Drawable, Acting, Healthy {
return this._color; return this._color;
} }
get stats(): PlayerStats { get effectiveStats(): PlayerStats {
return this._stats; return this._effectiveStats;
} }
get status(): PlayerStatus { get status(): PlayerStatus {
@@ -101,19 +112,30 @@ export class Player implements Drawable, Acting, Healthy {
} }
getSize() { getSize() {
return this.stats.size return this._effectiveStats.size
} }
dead() { dead() {
return this.status.dead return this.status.dead
} }
changeBaseStat(value: number, statFun: (stats: PlayerStats, value: number) => void) {
this._baseStats.changeStat(value, statFun)
this.statsChanged()
}
changeTempStat(value: number, statFun: (stats: PlayerStats, value: number) => void) {
this._tempStats.changeStat(value, statFun)
this.statsChanged()
}
increaseLevel() { increaseLevel() {
this.status.increaseLevel() this.status.increaseLevel()
this.stats.increaseLevel() this._baseStats.increaseLevel()
this._weapons.forEach(weapon => { this._weapons.forEach(weapon => {
weapon.increaseLevel() weapon.increaseLevel()
}) })
this.statsChanged()
} }
level() { level() {
@@ -179,6 +201,14 @@ export class PlayerStats {
this._weaponRangeFactor = 1; this._weaponRangeFactor = 1;
} }
resetToBasic() {
this._speed = 0;
this._health = 0;
this._pullRange = 0;
this._weaponRange = 0;
this._weaponRangeFactor = 1
}
increaseLevel() { increaseLevel() {
this._speed *= 1.1; this._speed *= 1.1;
this._health += 1 this._health += 1
@@ -187,29 +217,42 @@ export class PlayerStats {
this._weaponRangeFactor += 0.1 this._weaponRangeFactor += 0.1
} }
mergeStats(otherStats: PlayerStats) {
set speed(value: number) { this._speed += otherStats._speed;
this._speed = value; this._health += otherStats._health;
this._pullRange += otherStats._pullRange;
this._weaponRange += otherStats._weaponRange
this._weaponRangeFactor += otherStats._weaponRangeFactor;
} }
set size(value: number) { clone() {
this._size = value; let newStats = new PlayerStats();
newStats.mergeStats(this)
return newStats;
} }
set health(value: number) { changeStat(value: number, statFun: (stats: PlayerStats, value: number) => void) {
this._health = value; statFun(this, value)
} }
set pullRange(value: number) { static increaseSpeed(stats: PlayerStats, value: number) {
this._pullRange = value; stats._speed += value
} }
set weaponRange(value: number) { static factorSpeed(stats: PlayerStats, value: number) {
this._weaponRange = value; stats._speed *= value
} }
set weaponRangeFactor(value: number) { static increasePullRange(stats: PlayerStats, value: number) {
this._weaponRangeFactor = value; stats._pullRange += value
}
static factorPullRange(stats: PlayerStats, value: number) {
stats._pullRange += value
}
static increaseHealth(stats: PlayerStats, value: number) {
stats._health += value
} }
get speed(): number { get speed(): number {

View File

@@ -27,10 +27,10 @@ export abstract class BasicDrop implements Drop {
act() { act() {
let distanceToPlayer = this._position.distanceTo(this.world.player.position); let distanceToPlayer = this._position.distanceTo(this.world.player.position);
if(distanceToPlayer < (this.world.player.stats.size + this.size)) { if(distanceToPlayer < (this.world.player.effectiveStats.size + this.size)) {
this.pickup() this.pickup()
this.world.removeDrop(this) this.world.removeDrop(this)
} else if(distanceToPlayer < this.world.player.stats.pullRange) { } else if(distanceToPlayer < this.world.player.effectiveStats.pullRange) {
let speedFactor = 125 / distanceToPlayer; let speedFactor = 125 / distanceToPlayer;
this._position = moveInDirectionOf(this._position, this.world.player.position, speedFactor) this._position = moveInDirectionOf(this._position, this.world.player.position, speedFactor)
} }

View File

@@ -1,5 +1,5 @@
import type {ChanceEntry, Item} from "./interfaces.ts"; import type {ChanceEntry, Item} from "./interfaces.ts";
import {Player} from "./Player.ts"; import {Player, PlayerStats} from "./Player.ts";
import {randomItem} from "./utils.ts"; import {randomItem} from "./utils.ts";
import {ChainBall, HomingPistol, Pistol, Spear, SpreadWeapon} from "./weapons.ts"; import {ChainBall, HomingPistol, Pistol, Spear, SpreadWeapon} from "./weapons.ts";
import type {World} from "./World.ts"; import type {World} from "./World.ts";
@@ -85,7 +85,7 @@ export abstract class BaseItem implements Item {
export class SpeedUp extends BaseItem { export class SpeedUp extends BaseItem {
pickup(player: Player, world: World) { pickup(player: Player, world: World) {
player.stats.speed += 1 player.changeBaseStat(1, PlayerStats.increaseSpeed)
super.pickup(player, world) super.pickup(player, world)
} }
@@ -100,7 +100,7 @@ export class SpeedUp extends BaseItem {
export class PullRangeUp extends BaseItem { export class PullRangeUp extends BaseItem {
pickup(player: Player, world: World) { pickup(player: Player, world: World) {
player.stats.pullRange *= 1.1 player.changeBaseStat(1.1, PlayerStats.factorPullRange)
super.pickup(player, world) super.pickup(player, world)
} }
@@ -115,7 +115,7 @@ export class PullRangeUp extends BaseItem {
export class HealthUp extends BaseItem { export class HealthUp extends BaseItem {
pickup(player: Player, world: World) { pickup(player: Player, world: World) {
player.stats.health += 1 player.changeBaseStat(1, PlayerStats.increaseHealth)
super.pickup(player, world) super.pickup(player, world)
} }

View File

@@ -66,16 +66,16 @@ function makeKey(char, fun) {
let keys = {}; let keys = {};
makeKey('w', function (intensity: number) { makeKey('w', function (intensity: number) {
world.movePlayer(new Vector(0, -world.player.stats.speed * intensity)) world.movePlayer(new Vector(0, -world.player.effectiveStats.speed * intensity))
}) })
makeKey('s', function (intensity: number) { makeKey('s', function (intensity: number) {
world.movePlayer(new Vector(0, world.player.stats.speed * intensity)) world.movePlayer(new Vector(0, world.player.effectiveStats.speed * intensity))
}) })
makeKey('a', function (intensity: number) { makeKey('a', function (intensity: number) {
world.movePlayer(new Vector(-world.player.stats.speed * intensity, 0)) world.movePlayer(new Vector(-world.player.effectiveStats.speed * intensity, 0))
}) })
makeKey('d', function (intensity: number) { makeKey('d', function (intensity: number) {
world.movePlayer(new Vector(world.player.stats.speed * intensity, 0)) world.movePlayer(new Vector(world.player.effectiveStats.speed * intensity, 0))
}) })

View File

@@ -44,7 +44,7 @@ export abstract class Projectile implements Acting, Placeable {
act() { act() {
this.move() this.move()
if(this.parent !== this.world.player) { if(this.parent !== this.world.player) {
if(this.position.distanceTo(this.world.player.position) < (this.stats.size + this.world.player.stats.size) && this.status.collisionCooldown.cooledDown()) { if(this.position.distanceTo(this.world.player.position) < (this.stats.size + this.world.player.effectiveStats.size) && this.status.collisionCooldown.cooledDown()) {
this.impactPlayer() this.impactPlayer()
this.status.collisionCooldown.resetCooldown() this.status.collisionCooldown.resetCooldown()
} }
@@ -171,7 +171,7 @@ export class ChainBallProjectile extends Projectile {
} else { } else {
this.position = moveInDirectionOf(this.position, this.world.player.position, this.speedVec.vecLength()) this.position = moveInDirectionOf(this.position, this.world.player.position, this.speedVec.vecLength())
} }
if(this.movingBack && this.position.distanceTo(this.world.player.position) < (this.stats.size + this.world.player.stats.size)) { if(this.movingBack && this.position.distanceTo(this.world.player.position) < (this.stats.size + this.world.player.effectiveStats.size)) {
this.weapon.reset(); this.weapon.reset();
this.die() this.die()
} }
@@ -233,7 +233,7 @@ export class StraightMeleeWeaponProjectile extends Projectile {
} else { } else {
this.position = moveInDirectionOf(this.position, new Vector(0, 0), this.speedVec.vecLength()) this.position = moveInDirectionOf(this.position, new Vector(0, 0), this.speedVec.vecLength())
} }
if(this.movingBack && this.position.distanceTo(new Vector(0, 0)) < (this.stats.size + this.world.player.stats.size)) { if(this.movingBack && this.position.distanceTo(new Vector(0, 0)) < (this.stats.size + this.world.player.effectiveStats.size)) {
this.weapon.reset(); this.weapon.reset();
this.die() this.die()
} }

View File

@@ -120,14 +120,14 @@ export class PlayerInfo implements DrawContainer {
constructor(world: World) { constructor(world: World) {
this.world = world; this.world = world;
this.bar = new InfoBar(new Vector(0, 50), 50, 150, () => 'Health', () => this.world.player.status.health, () => this.world.player.stats.health) this.bar = new InfoBar(new Vector(0, 50), 50, 150, () => 'Health', () => this.world.player.status.health, () => this.world.player.effectiveStats.health)
this.statLabelBase = new Vector(0, 150) this.statLabelBase = new Vector(0, 150)
this.statLabels = [ this.statLabels = [
new StatLabel(() => 'Money', () => this.world.player.status.wealth), new StatLabel(() => 'Money', () => this.world.player.status.wealth),
new StatLabel(() => 'Level', () => this.world.player.status.level), new StatLabel(() => 'Level', () => this.world.player.status.level),
new StatLabel(() => 'Speed', () => Math.floor(this.world.player.stats.speed)), new StatLabel(() => 'Speed', () => Math.floor(this.world.player.effectiveStats.speed)),
new StatLabel(() => 'Pull range', () => Math.floor(this.world.player.stats.pullRange)), new StatLabel(() => 'Pull range', () => Math.floor(this.world.player.effectiveStats.pullRange)),
new StatLabel(() => 'Weapon range', () => Math.floor(this.world.player.stats.effectiveWeaponRange)) new StatLabel(() => 'Weapon range', () => Math.floor(this.world.player.effectiveStats.effectiveWeaponRange))
] ]
} }

View File

@@ -80,7 +80,7 @@ export abstract class RangeWeapon extends BasicWeapon {
} }
calculateRange(): number { calculateRange(): number {
return this.world.player.stats.effectiveWeaponRange + this.stats.effectiveWeaponRange; return this.world.player.effectiveStats.effectiveWeaponRange + this.stats.effectiveWeaponRange;
} }
} }