кровавые кролики жирнее
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
import { observer } from 'mobx-react-lite';
|
import { observer } from 'mobx-react-lite';
|
||||||
import type { GameStore } from '../game/GameStore';
|
import type { GameStore } from '../game/GameStore';
|
||||||
import type { RabbitState } from '../game/types';
|
import type { RabbitState } from '../game/types';
|
||||||
import { RABBIT_MAX_HP } from '../game/rabbits';
|
|
||||||
import { RABBIT_NIGHT_SPRITE, RABBIT_SPRITE } from '../game/sprites';
|
import { RABBIT_NIGHT_SPRITE, RABBIT_SPRITE } from '../game/sprites';
|
||||||
import HealthBar from './HealthBar';
|
import HealthBar from './HealthBar';
|
||||||
import PixelSprite from './PixelSprite';
|
import PixelSprite from './PixelSprite';
|
||||||
@@ -24,8 +23,8 @@ const RabbitEntity = observer(function RabbitEntity({ rabbit, store }: { rabbit:
|
|||||||
>
|
>
|
||||||
<PixelSprite pixels={store.isNight ? RABBIT_NIGHT_SPRITE : RABBIT_SPRITE} size={size} />
|
<PixelSprite pixels={store.isNight ? RABBIT_NIGHT_SPRITE : RABBIT_SPRITE} size={size} />
|
||||||
</div>
|
</div>
|
||||||
{rabbit.hp < RABBIT_MAX_HP && (
|
{rabbit.hp < store.rabbitMaxHp && (
|
||||||
<HealthBar x={rabbit.x} y={rabbit.y - rabbit.z - size * 0.5 - 6} ratio={rabbit.hp / RABBIT_MAX_HP} />
|
<HealthBar x={rabbit.x} y={rabbit.y - rabbit.z - size * 0.5 - 6} ratio={rabbit.hp / store.rabbitMaxHp} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
+26
-7
@@ -20,6 +20,7 @@ import {
|
|||||||
import { BLOOD_MOON_BANNER_SECONDS, DAY_HOURS, isBloodMoonNight, isNightHour, NIGHT_SPEED, nightBelongsToDay } from './daynight';
|
import { BLOOD_MOON_BANNER_SECONDS, DAY_HOURS, isBloodMoonNight, isNightHour, NIGHT_SPEED, nightBelongsToDay } from './daynight';
|
||||||
import { clearSave, loadSave, writeSave } from './persistence';
|
import { clearSave, loadSave, writeSave } from './persistence';
|
||||||
import {
|
import {
|
||||||
|
BLOOD_MOON_COMBAT_MULTIPLIER,
|
||||||
BLOOD_MOON_SIZE_MULTIPLIER,
|
BLOOD_MOON_SIZE_MULTIPLIER,
|
||||||
RABBIT_ACTION_DURATION,
|
RABBIT_ACTION_DURATION,
|
||||||
RABBIT_HEALTH_REGEN_INTERVAL,
|
RABBIT_HEALTH_REGEN_INTERVAL,
|
||||||
@@ -233,6 +234,17 @@ export class GameStore {
|
|||||||
return RABBIT_HIT_RADIUS * (this.isBloodMoon ? BLOOD_MOON_SIZE_MULTIPLIER : 1);
|
return RABBIT_HIT_RADIUS * (this.isBloodMoon ? BLOOD_MOON_SIZE_MULTIPLIER : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A rabbit's max hp — during a blood moon they're tougher, not just bigger. */
|
||||||
|
get rabbitMaxHp(): number {
|
||||||
|
return RABBIT_MAX_HP * (this.isBloodMoon ? BLOOD_MOON_COMBAT_MULTIPLIER : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Damage a rabbit's strike deals to the character — during a blood moon they hit harder, not
|
||||||
|
* just bigger. */
|
||||||
|
get rabbitStrikeDamage(): number {
|
||||||
|
return RABBIT_STRIKE_DAMAGE * (this.isBloodMoon ? BLOOD_MOON_COMBAT_MULTIPLIER : 1);
|
||||||
|
}
|
||||||
|
|
||||||
/** Buys the next level of the given upgrade if there are enough coins. Returns whether it bought. */
|
/** Buys the next level of the given upgrade if there are enough coins. Returns whether it bought. */
|
||||||
buyUpgrade(id: UpgradeId): boolean {
|
buyUpgrade(id: UpgradeId): boolean {
|
||||||
const level = this.upgradeLevels[id];
|
const level = this.upgradeLevels[id];
|
||||||
@@ -289,7 +301,7 @@ export class GameStore {
|
|||||||
// Recomputed from actionTime on the very next tick if actually mid-jump, so 0 is a safe
|
// Recomputed from actionTime on the very next tick if actually mid-jump, so 0 is a safe
|
||||||
// starting value regardless.
|
// starting value regardless.
|
||||||
z: 0,
|
z: 0,
|
||||||
hp: rabbit.hp ?? RABBIT_MAX_HP,
|
hp: rabbit.hp ?? this.rabbitMaxHp,
|
||||||
// Purely a transient visual cue — always starts unflashed regardless of the save.
|
// Purely a transient visual cue — always starts unflashed regardless of the save.
|
||||||
hitFlashTimer: 0,
|
hitFlashTimer: 0,
|
||||||
// Transient accumulator — always starts fresh regardless of the save.
|
// Transient accumulator — always starts fresh regardless of the save.
|
||||||
@@ -387,7 +399,7 @@ export class GameStore {
|
|||||||
x: pos.x,
|
x: pos.x,
|
||||||
y: pos.y,
|
y: pos.y,
|
||||||
z: 0,
|
z: 0,
|
||||||
hp: RABBIT_MAX_HP,
|
hp: this.rabbitMaxHp,
|
||||||
hitFlashTimer: 0,
|
hitFlashTimer: 0,
|
||||||
healthRegenProgress: 0,
|
healthRegenProgress: 0,
|
||||||
action: 'idle',
|
action: 'idle',
|
||||||
@@ -525,7 +537,8 @@ export class GameStore {
|
|||||||
this.updateAutosave(deltaTime);
|
this.updateAutosave(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Shows the "КРОВАВАЯ ЛУНА!" banner for a few seconds right as a blood moon night begins. */
|
/** Shows the "КРОВАВАЯ ЛУНА!" banner for a few seconds and heals every rabbit to full (their
|
||||||
|
* now-tripled max hp) right as a blood moon night begins. */
|
||||||
private updateBloodMoon(deltaTime: number) {
|
private updateBloodMoon(deltaTime: number) {
|
||||||
if (this.bloodMoonBannerTimer > 0)
|
if (this.bloodMoonBannerTimer > 0)
|
||||||
this.bloodMoonBannerTimer = Math.max(0, this.bloodMoonBannerTimer - deltaTime);
|
this.bloodMoonBannerTimer = Math.max(0, this.bloodMoonBannerTimer - deltaTime);
|
||||||
@@ -537,6 +550,11 @@ export class GameStore {
|
|||||||
return;
|
return;
|
||||||
this.lastAnnouncedBloodMoonDay = nightDay;
|
this.lastAnnouncedBloodMoonDay = nightDay;
|
||||||
this.bloodMoonBannerTimer = BLOOD_MOON_BANNER_SECONDS;
|
this.bloodMoonBannerTimer = BLOOD_MOON_BANNER_SECONDS;
|
||||||
|
const maxHp = this.rabbitMaxHp;
|
||||||
|
for (const rabbit of this.rabbits) {
|
||||||
|
rabbit.hp = maxHp;
|
||||||
|
rabbit.healthRegenProgress = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Hp regenerates a whole point at a time (same accumulate-then-spend cadence as chopProgress,
|
/** Hp regenerates a whole point at a time (same accumulate-then-spend cadence as chopProgress,
|
||||||
@@ -567,7 +585,7 @@ export class GameStore {
|
|||||||
* out — the ~1s of "striking" afterward is just the rabbit committed to that action and unable
|
* out — the ~1s of "striking" afterward is just the rabbit committed to that action and unable
|
||||||
* to do anything else, not a wind-up the character could still escape. */
|
* to do anything else, not a wind-up the character could still escape. */
|
||||||
private landRabbitStrike() {
|
private landRabbitStrike() {
|
||||||
this.characterHp = Math.max(0, this.characterHp - RABBIT_STRIKE_DAMAGE);
|
this.characterHp = Math.max(0, this.characterHp - this.rabbitStrikeDamage);
|
||||||
this.characterHitFlashTimer = HIT_FLASH_DURATION;
|
this.characterHitFlashTimer = HIT_FLASH_DURATION;
|
||||||
if (this.characterHp <= 0) {
|
if (this.characterHp <= 0) {
|
||||||
this.isDead = true;
|
this.isDead = true;
|
||||||
@@ -606,14 +624,15 @@ export class GameStore {
|
|||||||
* character's own regen — unlike the character's, this isn't paused by anything (no upgrade for
|
* character's own regen — unlike the character's, this isn't paused by anything (no upgrade for
|
||||||
* it either), so it ticks along even mid-fight. */
|
* it either), so it ticks along even mid-fight. */
|
||||||
private updateRabbitHealthRegen(rabbit: RabbitState, deltaTime: number) {
|
private updateRabbitHealthRegen(rabbit: RabbitState, deltaTime: number) {
|
||||||
if (rabbit.hp >= RABBIT_MAX_HP) {
|
const maxHp = this.rabbitMaxHp;
|
||||||
|
if (rabbit.hp >= maxHp) {
|
||||||
rabbit.healthRegenProgress = 0;
|
rabbit.healthRegenProgress = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
rabbit.healthRegenProgress += deltaTime;
|
rabbit.healthRegenProgress += deltaTime;
|
||||||
while (rabbit.healthRegenProgress >= RABBIT_HEALTH_REGEN_INTERVAL && rabbit.hp < RABBIT_MAX_HP) {
|
while (rabbit.healthRegenProgress >= RABBIT_HEALTH_REGEN_INTERVAL && rabbit.hp < maxHp) {
|
||||||
rabbit.healthRegenProgress -= RABBIT_HEALTH_REGEN_INTERVAL;
|
rabbit.healthRegenProgress -= RABBIT_HEALTH_REGEN_INTERVAL;
|
||||||
rabbit.hp = Math.min(RABBIT_MAX_HP, rabbit.hp + 1);
|
rabbit.hp = Math.min(maxHp, rabbit.hp + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,10 @@ export const RABBIT_NIGHT_JUMP_SPREAD_DEGREES = 30;
|
|||||||
/** Rabbits (and their strike/hit ranges) are this much bigger during a blood moon. */
|
/** Rabbits (and their strike/hit ranges) are this much bigger during a blood moon. */
|
||||||
export const BLOOD_MOON_SIZE_MULTIPLIER = 2;
|
export const BLOOD_MOON_SIZE_MULTIPLIER = 2;
|
||||||
|
|
||||||
|
/** Rabbits deal this much more strike damage and have this much more max hp during a blood moon —
|
||||||
|
* a bigger jump than their (purely visual/reach) size multiplier above. */
|
||||||
|
export const BLOOD_MOON_COMBAT_MULTIPLIER = 3;
|
||||||
|
|
||||||
/** Seconds per hp of rabbit health regen (fixed — unlike the character's own regen, there's no
|
/** Seconds per hp of rabbit health regen (fixed — unlike the character's own regen, there's no
|
||||||
* upgrade for it). */
|
* upgrade for it). */
|
||||||
export const RABBIT_HEALTH_REGEN_INTERVAL = 3;
|
export const RABBIT_HEALTH_REGEN_INTERVAL = 3;
|
||||||
|
|||||||
Reference in New Issue
Block a user