Combat: rewards on the kill, 1s pause, swing timer runs on between enemies
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
4cb6ff5ec0
commit
60b7b23a05
3 changed files with 61 additions and 15 deletions
24
game.py
24
game.py
|
|
@ -432,7 +432,7 @@ def _tiered_actions() -> list[dict]:
|
|||
# the trophies higher weapons need, and a boss.
|
||||
CRIT_CHANCE = 0.05
|
||||
CRIT_MULT = 1.5
|
||||
RESPAWN = 3 # seconds before the next enemy turns up
|
||||
RESPAWN = 1 # seconds after a kill before the next enemy turns up
|
||||
MAX_FIGHT = 600 # a fight that drags on longer is broken off
|
||||
FLEE_BELOW = 0.2 # out of food and under this share of HP: get out
|
||||
|
||||
|
|
@ -1195,8 +1195,12 @@ def fight_odds(player: dict, action: dict) -> dict:
|
|||
"kill_time": round(kill, 1), "damage": round(hurt, 1)}
|
||||
|
||||
|
||||
def simulate_fight(world: dict, player: dict, action: dict, rng: random.Random) -> dict:
|
||||
"""Play out one fight swing by swing. Nothing changes until it's over: the result is applied then."""
|
||||
def simulate_fight(world: dict, player: dict, action: dict, rng: random.Random, carry: float = 0) -> dict:
|
||||
"""Play out one fight swing by swing. Nothing changes until it's over: the result is applied then.
|
||||
|
||||
`carry` is how long ago (in game seconds) you last swung: your swing timer runs on from one
|
||||
enemy to the next, so outclassing an enemy means killing as fast as you can swing.
|
||||
"""
|
||||
foe, blessed, brew = action["enemy"], blessing(player), potion_effect(player, "combat")
|
||||
me = fighter(player, blessed, brew, foe)
|
||||
shrug = 0 if me["pierce"] else foe["reduction"]
|
||||
|
|
@ -1207,13 +1211,16 @@ def simulate_fight(world: dict, player: dict, action: dict, rng: random.Random)
|
|||
wind = blessed["wind"] and not (player["action"] or {}).get("wind_used")
|
||||
pace = speed(world)
|
||||
# A bow looses its first arrow before the enemy closes in.
|
||||
mine, theirs, result, t = (0.5 if me["first"] else me["interval"]), foe["interval"], None, 0.0
|
||||
ready = max(0.0, me["interval"] - carry)
|
||||
mine, theirs, result, t = (min(ready, 0.5) if me["first"] else ready), foe["interval"], None, 0.0
|
||||
swung = -carry
|
||||
while result is None:
|
||||
t = min(mine, theirs)
|
||||
if t > MAX_FIGHT:
|
||||
result = "fled"
|
||||
break
|
||||
if mine <= theirs:
|
||||
swung = mine
|
||||
mine += me["interval"]
|
||||
crit = rng.random() < me["crit"]
|
||||
landed = rng.random() < hit
|
||||
|
|
@ -1251,7 +1258,7 @@ def simulate_fight(world: dict, player: dict, action: dict, rng: random.Random)
|
|||
elif starving:
|
||||
result = "fled"
|
||||
return {"enemy": foe["name"], "enemy_hp": foe["hp"], "top": top, "start_hp": round(player["hp"]),
|
||||
"hp": hp, "result": result, "end": round(t / pace, 2), "duration": (t + RESPAWN) / pace,
|
||||
"hp": hp, "result": result, "end": round(t / pace, 2), "duration": t / pace, "carry": t - swung,
|
||||
"interval": me["interval"] / pace, "enemy_interval": foe["interval"] / pace, "events": events, "style": me["style"],
|
||||
"eaten": eaten, "damage": hurt, "pp": blessed["cost"],
|
||||
"wind_used": blessed["wind"] and not wind and not (player["action"] or {}).get("wind_used")}
|
||||
|
|
@ -1512,7 +1519,8 @@ def _complete(world: dict, player: dict, action: dict, now: float, rng: random.R
|
|||
|
||||
if "enemy" in action:
|
||||
outing = player["action"]
|
||||
fight = outing.pop("fight", None) or simulate_fight(world, player, action, rng)
|
||||
fight = outing.pop("fight", None) or simulate_fight(world, player, action, rng, outing.get("carry", 0))
|
||||
outing["carry"] = fight.get("carry", 0) + RESPAWN # fights from before the carry-over have none
|
||||
if player["prayers"] and not fight["pp"]:
|
||||
summary["prayer_out"] = True
|
||||
paid = min(player["pp"], fight["pp"])
|
||||
|
|
@ -1639,7 +1647,7 @@ def process_player(world: dict, player: dict, now: float, rng: random.Random | N
|
|||
if "enemy" in action and not can_start(world, player, action):
|
||||
if not current.get("fight"):
|
||||
regen(world, player, current["start"], blessing(player)["regen"])
|
||||
current["fight"] = simulate_fight(world, player, action, rng)
|
||||
current["fight"] = simulate_fight(world, player, action, rng, current.get("carry", 0))
|
||||
duration = current["fight"]["duration"]
|
||||
else:
|
||||
duration = action_time(world, player, action)
|
||||
|
|
@ -1667,6 +1675,8 @@ def process_player(world: dict, player: dict, now: float, rng: random.Random | N
|
|||
_complete(world, player, action, current["start"] + duration, rng, summary)
|
||||
summary["done"] += 1
|
||||
current["start"] += duration
|
||||
if "enemy" in action and player["action"] is current:
|
||||
current["start"] += RESPAWN / speed(world) # a moment before the next enemy turns up
|
||||
if current.get("plot2"):
|
||||
current["turn"] = 1 - current.get("turn", 0)
|
||||
if player["action"] is current and "left" in current:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue