Drilling scales with the threat, like scouting
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
1c80bd80f7
commit
b248a030ea
4 changed files with 50 additions and 31 deletions
37
game.py
37
game.py
|
|
@ -371,7 +371,7 @@ ACTIONS = [
|
|||
_action("cook_meat", "cooking", "Cooked meat", 5, 20, 7, {"raw_meat": 1, "logs": 1}, {"cooked_meat": 1}),
|
||||
_action("cook_stew", "cooking", "Stew", 15, 35, 16,
|
||||
{"raw_meat": 1, "vegetables": 2, "logs": 1}, {"stew": 2}),
|
||||
_action("drill_militia", "combat", "Drill the militia", 1, 50, 10, special="drill"),
|
||||
_action("drill_militia", "combat", "Drill the militia", 1, 60, 12, special="drill"),
|
||||
_action("fight_wolves", "combat", "Wolves in the woods", 1, 60, 14, difficulty=2, damage=2, gold=2,
|
||||
drops=[["raw_meat", 1, 0.6], ["hide", 1, 0.5], ["bones", 1, 1.0]]),
|
||||
_action("fight_scouts", "combat", "Bandit scouts", 10, 75, 30, difficulty=14, damage=6, gold=10,
|
||||
|
|
@ -1021,7 +1021,7 @@ def can_start(world: dict, player: dict, action: dict) -> str | None:
|
|||
threat = upcoming_raid(world)
|
||||
if not threat:
|
||||
return "No raid to prepare for"
|
||||
if threat.get("drilled", 0) >= drill_cap(world):
|
||||
if threat.get("drilled", 0) >= drill_needed(threat):
|
||||
return "The militia is as drilled as it can be"
|
||||
if "difficulty" in action and player["hp"] < max_hp(player) * TOO_HURT and not edible(player):
|
||||
return "Too hurt to fight. Rest, or bring food"
|
||||
|
|
@ -1120,7 +1120,7 @@ def _complete(world: dict, player: dict, action: dict, now: float, rng: random.R
|
|||
boost = min(city.get("drill_boost", 0), gain)
|
||||
city["drill_boost"] = city.get("drill_boost", 0) - boost
|
||||
xp = DRILL_XP * (gain + boost) * mods["xp"]
|
||||
threat["drilled"] = min(drill_cap(world), threat.get("drilled", 0) + gain + boost)
|
||||
threat["drilled"] = min(drill_needed(threat), threat.get("drilled", 0) + gain + boost)
|
||||
if action.get("special") == "labour":
|
||||
city = world["city"]
|
||||
site = city["construction"]
|
||||
|
|
@ -2510,17 +2510,22 @@ def happenings_view(world: dict, now: float) -> dict:
|
|||
MASTER_BUILDER_LABOUR = 50 # boosted labour per hire: doubled labour and XP for whoever works it
|
||||
MASTER_BUILDER_FAVOUR = 150 # +50% for every further hire on the same site
|
||||
INFORMANT_FAVOUR = 250
|
||||
# Drilling: fighters train the townsfolk before a raid, a little defence per
|
||||
# session (more for a seasoned fighter), up to half the population.
|
||||
DRILL_PER_ACTION = 0.5 # plus as much again every 20 combat levels
|
||||
DRILL_XP = 20 # combat XP per point of defence drilled
|
||||
DRILL_SHARE = 0.5 # most drilled defence: this much per townsperson
|
||||
DRILL_SERGEANT_POINTS = 15 # boosted drilling per hire: doubled defence and XP
|
||||
# Drilling: fighters train the townsfolk before a raid. A full drill takes as
|
||||
# many points as full intel on the same threat, so fighters and scouts put in
|
||||
# about the same time; the defence it's worth grows with the population.
|
||||
DRILL_PER_ACTION = 1.0 # drill points per session, +25% every 20 combat levels
|
||||
DRILL_XP = 12 # combat XP per drill point
|
||||
DRILL_SHARE = 1.0 # defence of a fully drilled militia, per townsperson
|
||||
DRILL_SERGEANT_POINTS = 30 # boosted drilling per hire: doubled points and XP
|
||||
DRILL_SERGEANT_FAVOUR = 150 # +50% for every further hire against the same threat
|
||||
|
||||
|
||||
def drill_per_action(player: dict) -> float:
|
||||
return DRILL_PER_ACTION * (1 + skill_level(player, "combat") // 20)
|
||||
return DRILL_PER_ACTION * (1 + 0.25 * (skill_level(player, "combat") // 20))
|
||||
|
||||
|
||||
def drill_needed(threat: dict) -> int:
|
||||
return intel_costs(threat)[-1]
|
||||
|
||||
|
||||
def drill_cap(world: dict) -> float:
|
||||
|
|
@ -2528,8 +2533,11 @@ def drill_cap(world: dict) -> float:
|
|||
|
||||
|
||||
def drilled(world: dict) -> float:
|
||||
"""Defence the drilling is worth so far: a share of the cap, as far as the drill has got."""
|
||||
threat = upcoming_raid(world)
|
||||
return min(drill_cap(world), threat.get("drilled", 0)) if threat else 0
|
||||
if not threat:
|
||||
return 0
|
||||
return drill_cap(world) * min(1.0, threat.get("drilled", 0) / drill_needed(threat))
|
||||
|
||||
|
||||
def favours(world: dict, now: float) -> dict:
|
||||
|
|
@ -2556,10 +2564,11 @@ def favours(world: dict, now: float) -> dict:
|
|||
"sergeant": {
|
||||
"cost": round(DRILL_SERGEANT_FAVOUR * (1 + 0.5 * (raid or {}).get("sergeants", 0))),
|
||||
"why": "No raid to prepare for" if not raid else
|
||||
"The militia is as drilled as it can be" if drilled(world) >= drill_cap(world) else None,
|
||||
"The militia is as drilled as it can be" if raid.get("drilled", 0) >= drill_needed(raid) else None,
|
||||
"drill": DRILL_SERGEANT_POINTS,
|
||||
"boost": round(city.get("drill_boost", 0), 1),
|
||||
"drilled": round(drilled(world), 1), "cap": drill_cap(world),
|
||||
"points": int((raid or {}).get("drilled", 0)), "needed": drill_needed(raid) if raid else 0,
|
||||
"defence": round(drilled(world), 1), "cap": drill_cap(world),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -2593,7 +2602,7 @@ def spend_favour(world: dict, player: dict, kind: str, now: float) -> str | None
|
|||
raid["sergeants"] = raid.get("sergeants", 0) + 1
|
||||
city["drill_boost"] = city.get("drill_boost", 0) + DRILL_SERGEANT_POINTS
|
||||
log(world, now, "favour", f"{player['name']} hired a drill sergeant: the next {DRILL_SERGEANT_POINTS} "
|
||||
f"drilled defence counts double", player["id"])
|
||||
f"drill points count double", player["id"])
|
||||
return None
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue