Prayer: bury on the spot, retuned costs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
40e5274c4e
commit
a7ff97815f
5 changed files with 106 additions and 32 deletions
12
README.md
12
README.md
|
|
@ -145,11 +145,13 @@ Beta. The core game is in place; changes from here are mostly balance and tuning
|
||||||
them a day, so it slows as the houses fill, plus slow family growth); it promotes the settlement
|
them a day, so it slows as the houses fill, plus slow family growth); it promotes the settlement
|
||||||
(hamlet, village at 40, town at 90, city at 150), which raises building
|
(hamlet, village at 40, town at 90, city at 150), which raises building
|
||||||
level caps and gives everyone bank slots.
|
level caps and gives everyone bank slots.
|
||||||
- **Prayer:** enemies drop bones; burying them gives prayer points and
|
- **Prayer:** enemies drop bones, which are buried on the spot for prayer
|
||||||
Prayer XP. Up to two prayers (eight unlock from level 1 to 60) boost each
|
points and half the XP of burying by hand (a setting; off sends them to
|
||||||
fight while their points last, and praying trains Prayer too. A Temple adds
|
the bank, to bury by hand for full XP). Up to two prayers (eight unlock from level 1 to 60) boost each
|
||||||
points per bone and lets players offer bones as devotion, which wards the
|
fight while their points last, and praying trains Prayer. Early in each
|
||||||
city in the next raid.
|
bone tier bones cover two prayers; later a Prayer potion makes up the gap.
|
||||||
|
A Temple adds 25% points from bones a level and lets players offer bones as
|
||||||
|
devotion, which wards the city in the next raid.
|
||||||
- **Herblore:** farmers grow six herbs (guam to snapdragon), one per tier.
|
- **Herblore:** farmers grow six herbs (guam to snapdragon), one per tier.
|
||||||
Every potion is a ladder of up to six tiers (I–VI): the tier's herb plus
|
Every potion is a ladder of up to six tiers (I–VI): the tier's herb plus
|
||||||
the matching rung of the skill's own resources (copper ore → runite ore,
|
the matching rung of the skill's own resources (copper ore → runite ore,
|
||||||
|
|
|
||||||
3
app.py
3
app.py
|
|
@ -499,6 +499,9 @@ class Handler(BaseHTTPRequestHandler):
|
||||||
if path == "/api/track":
|
if path == "/api/track":
|
||||||
return game.toggle_track(player, str(body.get("id")))
|
return game.toggle_track(player, str(body.get("id")))
|
||||||
if path == "/api/settings":
|
if path == "/api/settings":
|
||||||
|
if isinstance(body.get("bury"), bool):
|
||||||
|
player["bury"] = body["bury"]
|
||||||
|
return None
|
||||||
if body.get("overflow") not in ("city", "stop"):
|
if body.get("overflow") not in ("city", "stop"):
|
||||||
return "Bad setting"
|
return "Bad setting"
|
||||||
player["overflow"] = body["overflow"]
|
player["overflow"] = body["overflow"]
|
||||||
|
|
|
||||||
72
game.py
72
game.py
|
|
@ -1291,8 +1291,8 @@ ACTIONS = [
|
||||||
_action("pack_fish", "cooking", "Pack fish rations", 1, 20, 6, {"cooked_shrimp": 2}, {"provisions": 1}, group="Rations"),
|
_action("pack_fish", "cooking", "Pack fish rations", 1, 20, 6, {"cooked_shrimp": 2}, {"provisions": 1}, group="Rations"),
|
||||||
_action("drill_militia", "combat", "Drill the militia", 1, 60, 12, special="drill", group="Frontier"),
|
_action("drill_militia", "combat", "Drill the militia", 1, 60, 12, special="drill", group="Frontier"),
|
||||||
_action("bury_bones", "prayer", "Bury bones", 1, 10, 4, {"bones": 1}, special="bury", pp=2, group="Bury"),
|
_action("bury_bones", "prayer", "Bury bones", 1, 10, 4, {"bones": 1}, special="bury", pp=2, group="Bury"),
|
||||||
_action("bury_big_bones", "prayer", "Bury big bones", 15, 10, 15, {"big_bones": 1}, special="bury", pp=6, group="Bury"),
|
_action("bury_big_bones", "prayer", "Bury big bones", 15, 10, 15, {"big_bones": 1}, special="bury", pp=3, group="Bury"),
|
||||||
_action("bury_dragon_bones", "prayer", "Bury dragon bones", 40, 12, 72, {"dragon_bones": 1}, special="bury", pp=20, group="Bury"),
|
_action("bury_dragon_bones", "prayer", "Bury dragon bones", 40, 12, 72, {"dragon_bones": 1}, special="bury", pp=5, group="Bury"),
|
||||||
_action("offer_bones", "prayer", "Offer bones at the temple", 1, 12, 7, {"bones": 1}, special="offer",
|
_action("offer_bones", "prayer", "Offer bones at the temple", 1, 12, 7, {"bones": 1}, special="offer",
|
||||||
devotion=2, city={"temple": 1}, group="Offer at the temple"),
|
devotion=2, city={"temple": 1}, group="Offer at the temple"),
|
||||||
_action("offer_big_bones", "prayer", "Offer big bones", 15, 12, 25, {"big_bones": 1}, special="offer",
|
_action("offer_big_bones", "prayer", "Offer big bones", 15, 12, 25, {"big_bones": 1}, special="offer",
|
||||||
|
|
@ -1452,7 +1452,7 @@ BUILDINGS = {
|
||||||
"base": {"stone": 700, "bricks": 200, "cut_stone": 60, "provisions": 60},
|
"base": {"stone": 700, "bricks": 200, "cut_stone": 60, "provisions": 60},
|
||||||
"advanced": {"beam": 15, "rope": 40, "iron_nails": 150},
|
"advanced": {"beam": 15, "rope": 40, "iron_nails": 150},
|
||||||
"late": {"willow_logs": 80, "oak_plank": 35, "hide_glue": 40, "steel_hinges": 20},
|
"late": {"willow_logs": 80, "oak_plank": 35, "hide_glue": 40, "steel_hinges": 20},
|
||||||
"effect": "Per level: +1 prayer point per bone, +25% devotion",
|
"effect": "Per level: +25% prayer points from bones, +25% devotion",
|
||||||
},
|
},
|
||||||
"granary": {
|
"granary": {
|
||||||
"name": "Granary", "icon": "🌾", "max": 3, "gold": 150,
|
"name": "Granary", "icon": "🌾", "max": 3, "gold": 150,
|
||||||
|
|
@ -1524,7 +1524,7 @@ RAID_TRAITS = ["lightly armoured, heavy on archers", "mounted and fast, few bows
|
||||||
|
|
||||||
# --- world ---------------------------------------------------------------
|
# --- world ---------------------------------------------------------------
|
||||||
|
|
||||||
WORLD_VERSION = 32
|
WORLD_VERSION = 33
|
||||||
|
|
||||||
|
|
||||||
def new_world(now: float, speed: float = 1.0) -> dict:
|
def new_world(now: float, speed: float = 1.0) -> dict:
|
||||||
|
|
@ -1775,6 +1775,11 @@ def migrate(world: dict, now: float | None = None) -> dict:
|
||||||
for player in world["players"].values():
|
for player in world["players"].values():
|
||||||
player.setdefault("queue", [])
|
player.setdefault("queue", [])
|
||||||
world["version"] = 32
|
world["version"] = 32
|
||||||
|
if world["version"] < 33:
|
||||||
|
# Bury on the spot: fight bones go straight to prayer points.
|
||||||
|
for player in world["players"].values():
|
||||||
|
player.setdefault("bury", True)
|
||||||
|
world["version"] = 33
|
||||||
return world
|
return world
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2030,7 +2035,7 @@ def new_player(uid: str, name: str, cls: str, now: float) -> dict:
|
||||||
"pp": 0, "prayers": [], "potions": {},
|
"pp": 0, "prayers": [], "potions": {},
|
||||||
"hp": 44, "hp_at": now,
|
"hp": 44, "hp_at": now,
|
||||||
"action": None, "stopped": None, "queue": [],
|
"action": None, "stopped": None, "queue": [],
|
||||||
"last_active": now, "overflow": "city",
|
"last_active": now, "overflow": "city", "bury": True,
|
||||||
"perks": {"bank_slot": 0}, "manual": [], "patterns": [], "found": [], "eat_below": EAT_BELOW,
|
"perks": {"bank_slot": 0}, "manual": [], "patterns": [], "found": [], "eat_below": EAT_BELOW,
|
||||||
"rented": 0, "boosts": [], "bought": None, "deeds": {}, "owned": [], "look": dict(DEFAULT_LOOK),
|
"rented": 0, "boosts": [], "bought": None, "deeds": {}, "owned": [], "look": dict(DEFAULT_LOOK),
|
||||||
"garrison": False,
|
"garrison": False,
|
||||||
|
|
@ -2499,18 +2504,18 @@ def pack_xp(fight: dict, killed_only: bool = False) -> float:
|
||||||
MEND = 0.0004 # Rapid Heal: share of max HP mended per second of fighting
|
MEND = 0.0004 # Rapid Heal: share of max HP mended per second of fighting
|
||||||
|
|
||||||
PRAYERS = [
|
PRAYERS = [
|
||||||
{"id": "thick_skin", "name": "Thick Skin", "icon": "🪨", "level": 1, "cost": 1, "reduce": 0.10},
|
{"id": "thick_skin", "name": "Thick Skin", "icon": "🪨", "level": 1, "cost": 2, "reduce": 0.10},
|
||||||
{"id": "burst_of_strength", "name": "Burst of Strength", "icon": "💪", "level": 5, "cost": 1, "power": 5},
|
{"id": "burst_of_strength", "name": "Burst of Strength", "icon": "💪", "level": 5, "cost": 2, "power": 5},
|
||||||
{"id": "rapid_heal", "name": "Rapid Heal", "icon": "💗", "level": 10, "cost": 1, "mend": MEND},
|
{"id": "rapid_heal", "name": "Rapid Heal", "icon": "💗", "level": 10, "cost": 3, "mend": MEND},
|
||||||
{"id": "steel_skin", "name": "Steel Skin", "icon": "🛡️", "level": 20, "cost": 2, "reduce": 0.20},
|
{"id": "steel_skin", "name": "Steel Skin", "icon": "🛡️", "level": 20, "cost": 4, "reduce": 0.20},
|
||||||
{"id": "superhuman_strength", "name": "Superhuman Strength", "icon": "🦾", "level": 30, "cost": 2, "power": 12},
|
{"id": "superhuman_strength", "name": "Superhuman Strength", "icon": "🦾", "level": 30, "cost": 6, "power": 12},
|
||||||
{"id": "second_wind", "name": "Second Wind", "icon": "🌬️", "level": 40, "cost": 1, "wind": True},
|
{"id": "second_wind", "name": "Second Wind", "icon": "🌬️", "level": 40, "cost": 3, "wind": True},
|
||||||
{"id": "protection", "name": "Protection", "icon": "✨", "level": 50, "cost": 3, "reduce": 0.35},
|
{"id": "protection", "name": "Protection", "icon": "✨", "level": 50, "cost": 9, "reduce": 0.35},
|
||||||
{"id": "piety", "name": "Piety", "icon": "😇", "level": 60, "cost": 4, "power": 20, "reduce": 0.20},
|
{"id": "piety", "name": "Piety", "icon": "😇", "level": 60, "cost": 12, "power": 20, "reduce": 0.20},
|
||||||
]
|
]
|
||||||
PRAYER_BY_ID = {prayer["id"]: prayer for prayer in PRAYERS}
|
PRAYER_BY_ID = {prayer["id"]: prayer for prayer in PRAYERS}
|
||||||
MAX_PRAYERS = 2
|
MAX_PRAYERS = 2
|
||||||
PRAYER_XP_PER_POINT = 5
|
PRAYER_XP_PER_POINT = 3
|
||||||
NO_BLESSING = {"cost": 0, "power": 0, "taken": 1.0, "mend": 0, "wind": False}
|
NO_BLESSING = {"cost": 0, "power": 0, "taken": 1.0, "mend": 0, "wind": False}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2554,8 +2559,34 @@ def set_prayers(player: dict, ids: list) -> str | None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def bone_points(world: dict, action: dict) -> int:
|
def bone_points(world: dict, action: dict) -> float:
|
||||||
return action["pp"] + building_level(world, "temple") + fitted(world, "carved_altar")
|
return action["pp"] * (1 + 0.25 * (building_level(world, "temple") + fitted(world, "carved_altar")))
|
||||||
|
|
||||||
|
|
||||||
|
BURY_LEVEL = {bone: ACTION_BY_ID[f"bury_{bone}"]["level"] for bone in ("bones", "big_bones", "dragon_bones")}
|
||||||
|
SPOT_BURY_XP = 0.5 # burying on the spot gives half the XP of burying by hand
|
||||||
|
|
||||||
|
|
||||||
|
def bury_on_the_spot(world: dict, player: dict, drops: dict, now: float, summary: dict) -> dict:
|
||||||
|
"""A won fight's bones go straight into prayer points and half the XP of burying by hand. Bones
|
||||||
|
above the player's Prayer level, or everything with the setting off, go to the bank."""
|
||||||
|
if not player.get("bury", True):
|
||||||
|
return drops
|
||||||
|
kept = dict(drops)
|
||||||
|
for bone, level in BURY_LEVEL.items():
|
||||||
|
count = kept.get(bone, 0)
|
||||||
|
if not count or skill_level(player, "prayer") < level:
|
||||||
|
continue
|
||||||
|
del kept[bone]
|
||||||
|
action = ACTION_BY_ID[f"bury_{bone}"]
|
||||||
|
for _ in range(count):
|
||||||
|
points = bone_points(world, action) * (1 + potion_effect(player, "prayer").get("bones", 0))
|
||||||
|
player["pp"] += points
|
||||||
|
summary["pp_gained"] += points
|
||||||
|
_use_charge(player, "prayer", summary)
|
||||||
|
xp = action["xp"] * count * SPOT_BURY_XP * skill_mods(world, action)["xp"]
|
||||||
|
gain_xp(world, player, "prayer", xp, now, summary)
|
||||||
|
return kept
|
||||||
|
|
||||||
|
|
||||||
def ward(world: dict) -> float:
|
def ward(world: dict) -> float:
|
||||||
|
|
@ -2944,7 +2975,7 @@ def _complete(world: dict, player: dict, action: dict, now: float, rng: random.R
|
||||||
player["owned"].append(emblem)
|
player["owned"].append(emblem)
|
||||||
player["gold"] += gold
|
player["gold"] += gold
|
||||||
summary["gold"] += gold
|
summary["gold"] += gold
|
||||||
for item, qty in drops.items():
|
for item, qty in bury_on_the_spot(world, player, drops, now, summary).items():
|
||||||
outputs[item] = outputs.get(item, 0) + qty
|
outputs[item] = outputs.get(item, 0) + qty
|
||||||
if action.get("special") == "sabotage":
|
if action.get("special") == "sabotage":
|
||||||
raid = upcoming_raid(world)
|
raid = upcoming_raid(world)
|
||||||
|
|
@ -4887,7 +4918,7 @@ FITTINGS = [
|
||||||
("bellows", "Great bellows", "smithy", 3, 50, {"maple_plank": 30, "bear_leather": 15, "mithril_brackets": 6},
|
("bellows", "Great bellows", "smithy", 3, 50, {"maple_plank": 30, "bear_leather": 15, "mithril_brackets": 6},
|
||||||
"Smithing 10% faster", "bellows", "#d0663a"),
|
"Smithing 10% faster", "bellows", "#d0663a"),
|
||||||
("carved_altar", "Carved altar", "temple", 2, 60, {"yew_plank": 30, "cut_stone": 60, "adamant_chain": 4},
|
("carved_altar", "Carved altar", "temple", 2, 60, {"yew_plank": 30, "cut_stone": 60, "adamant_chain": 4},
|
||||||
"+1 prayer point per bone, ward +15", "star-altar", "#6f9a4a"),
|
"+25% prayer points from bones, ward +15", "star-altar", "#6f9a4a"),
|
||||||
("enchanted_chests", "Enchanted chests", "storehouse", 4, 75, {"magic_plank": 40, "rune_lock": 6},
|
("enchanted_chests", "Enchanted chests", "storehouse", 4, 75, {"magic_plank": 40, "rune_lock": 6},
|
||||||
"+500 stack size", "open-treasure-chest", "#a77be8"),
|
"+500 stack size", "open-treasure-chest", "#a77be8"),
|
||||||
("enchanted_hearths", "Enchanted hearths", "houses", 4, 80, {"magic_plank": 50, "mammoth_leather": 5, "adamant_chain": 6},
|
("enchanted_hearths", "Enchanted hearths", "houses", 4, 80, {"magic_plank": 50, "mammoth_leather": 5, "adamant_chain": 6},
|
||||||
|
|
@ -6162,6 +6193,11 @@ ORDER_RECIPES, ORDER_RAW = _order_sources()
|
||||||
# What changed, shown on the Patch notes page. Newest first; every shipped change adds a
|
# What changed, shown on the Patch notes page. Newest first; every shipped change adds a
|
||||||
# line here (new / balance / fix), and a new release a new entry on top.
|
# line here (new / balance / fix), and a new release a new entry on top.
|
||||||
PATCH_NOTES = [
|
PATCH_NOTES = [
|
||||||
|
{"date": "2026-10-27", "title": "Prayer", "notes": [
|
||||||
|
("new", "Bury on the spot: bones from combat turns into prayer points and 1/2 bury XP as they drop. Toggle in the Prayer menu."),
|
||||||
|
("balance", "Prayer costs adjusted."),
|
||||||
|
("balance", "Prayer potions now relevant for new costs."),
|
||||||
|
]},
|
||||||
{"date": "2026-10-26", "title": "Fittings", "notes": [
|
{"date": "2026-10-26", "title": "Fittings", "notes": [
|
||||||
("new", "Guild Roster shows player activity."),
|
("new", "Guild Roster shows player activity."),
|
||||||
("new", "Make X: \"Make one\" takes a count (1–1,000), then back to what you were doing."),
|
("new", "Make X: \"Make one\" takes a count (1–1,000), then back to what you were doing."),
|
||||||
|
|
|
||||||
|
|
@ -1231,6 +1231,13 @@ function drawFlame(cv, id, n) {
|
||||||
ctx.globalAlpha = 1;
|
ctx.globalAlpha = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Temple levels and its carved altar: +25% prayer points from bones each.
|
||||||
|
function bonePercent() {
|
||||||
|
const temple = S.city.buildings.temple;
|
||||||
|
if (temple?.damaged) return 0;
|
||||||
|
return 25 *((temple?.level || 0) + (temple?.fittings || []).includes("carved_altar"));
|
||||||
|
}
|
||||||
|
|
||||||
function prayerPanel() {
|
function prayerPanel() {
|
||||||
const me = S.me, city = S.city, level = me.levels.prayer;
|
const me = S.me, city = S.city, level = me.levels.prayer;
|
||||||
const cost = C.prayers.filter((p) => me.prayers.includes(p.id)).reduce((sum, p) => sum + p.cost, 0);
|
const cost = C.prayers.filter((p) => me.prayers.includes(p.id)).reduce((sum, p) => sum + p.cost, 0);
|
||||||
|
|
@ -1244,16 +1251,19 @@ function prayerPanel() {
|
||||||
<span class="small ${locked ? "why" : "muted"}">${locked ? `Lv ${p.level}` : `${p.cost} pt${p.cost > 1 ? "s" : ""}/fight`}</span>
|
<span class="small ${locked ? "why" : "muted"}">${locked ? `Lv ${p.level}` : `${p.cost} pt${p.cost > 1 ? "s" : ""}/fight`}</span>
|
||||||
</button>`;
|
</button>`;
|
||||||
}).join("");
|
}).join("");
|
||||||
const temple = city.buildings.temple.level;
|
const temple = city.buildings.temple.level, boost = bonePercent();
|
||||||
|
const bury = me.bury !== false;
|
||||||
return `<div class="cols">
|
return `<div class="cols">
|
||||||
<div class="panel"><h2>Prayers · ${me.prayers.length} / ${C.max_prayers} active</h2>
|
<div class="panel"><h2>Prayers · ${me.prayers.length} / ${C.max_prayers} active</h2>
|
||||||
<div class="prayer-points">${skillOf("prayer").icon} <b>${fmt(me.pp)}</b> prayer points${cost ? ` · ${cost} per fight (~${fmt(me.pp / cost)} fights)` : ""}</div>
|
<div class="prayer-points">${skillOf("prayer").icon} <b>${fmt(me.pp)}</b> prayer points${cost ? ` · ${cost} per fight (~${fmt(me.pp / cost)} fights)` : ""}</div>
|
||||||
<div class="prayers">${cards}</div>
|
<div class="prayers">${cards}</div>
|
||||||
<p class="small muted">Prayers cost points each fight. Bury bones for more.</p>
|
<div class="row"><button class="btn sm ${bury ? "gold" : ""}" data-bury="${bury ? "off" : "on"}"
|
||||||
|
title="Fight bones turn into prayer points and ½ bury XP as they drop. Off: they go to the bank.">🦴 Bury on the spot: ${bury ? "on" : "off"}</button></div>
|
||||||
|
<p class="small muted">Prayers cost points each fight; bones refill them.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel"><h2>Temple</h2>
|
<div class="panel"><h2>Temple</h2>
|
||||||
${temple ? `<p>Devotion <b>${fmt(city.devotion)}</b> · ward <b>+${city.ward}</b> defence (max +${15 * temple})</p>
|
${temple ? `<p>Devotion <b>${fmt(city.devotion)}</b> · ward <b>+${city.ward}</b> defence (max +${15 * temple})</p>
|
||||||
<p class="small muted">Offerings ward the next raid. +${temple} prayer point${temple > 1 ? "s" : ""} per bone buried.</p>`
|
<p class="small muted">Offerings ward the next raid. +${boost}% prayer points from bones.</p>`
|
||||||
: `<p class="muted">No temple yet.</p>`}
|
: `<p class="muted">No temple yet.</p>`}
|
||||||
</div></div>`;
|
</div></div>`;
|
||||||
}
|
}
|
||||||
|
|
@ -1724,7 +1734,7 @@ function actionCard(a) {
|
||||||
if (a.special === "labour") {
|
if (a.special === "labour") {
|
||||||
extra = `<div class="small makes">${skillOf("construction").icon} +${me.labour_per_action} labour per action</div>`;
|
extra = `<div class="small makes">${skillOf("construction").icon} +${me.labour_per_action} labour per action</div>`;
|
||||||
}
|
}
|
||||||
if (a.special === "bury") extra = `<div class="small makes">${skillOf("prayer").icon} +${a.pp + temple} prayer points</div>`;
|
if (a.special === "bury") extra = `<div class="small makes">${skillOf("prayer").icon} +${+(a.pp * (1 + bonePercent() / 100)).toFixed(2)} prayer points</div>`;
|
||||||
if (a.special === "offer") extra = `<div class="small makes">${C.buildings.temple.icon} +${+(a.devotion * (1 + 0.25 * temple)).toFixed(1)} devotion</div>`;
|
if (a.special === "offer") extra = `<div class="small makes">${C.buildings.temple.icon} +${+(a.devotion * (1 + 0.25 * temple)).toFixed(1)} devotion</div>`;
|
||||||
const gear = Object.keys(a.outputs).filter((id) => GEAR_SLOTS.includes(item(id).slot));
|
const gear = Object.keys(a.outputs).filter((id) => GEAR_SLOTS.includes(item(id).slot));
|
||||||
const made = Object.keys(a.outputs).filter((id) => !gear.includes(id)).map(itemStats).filter(Boolean);
|
const made = Object.keys(a.outputs).filter((id) => !gear.includes(id)).map(itemStats).filter(Boolean);
|
||||||
|
|
@ -2925,6 +2935,7 @@ document.addEventListener("click", (e) => {
|
||||||
return act("/api/prayers", { ids: on ? S.me.prayers.filter((x) => x !== d.pray) : [...S.me.prayers, d.pray] });
|
return act("/api/prayers", { ids: on ? S.me.prayers.filter((x) => x !== d.pray) : [...S.me.prayers, d.pray] });
|
||||||
}
|
}
|
||||||
if (d.overflow) return act("/api/settings", { overflow: d.overflow });
|
if (d.overflow) return act("/api/settings", { overflow: d.overflow });
|
||||||
|
if (d.bury) return act("/api/settings", { bury: d.bury === "on" });
|
||||||
if (d.class) { pickedClass = d.class; render(); return; }
|
if (d.class) { pickedClass = d.class; render(); return; }
|
||||||
if ("repick" in d) return act("/api/class", { cls: pickedClass });
|
if ("repick" in d) return act("/api/class", { cls: pickedClass });
|
||||||
if (d.tab) { tabs[d.tab] = d.group; remember(`tab.${d.tab}`, d.group); render(); return; }
|
if (d.tab) { tabs[d.tab] = d.group; remember(`tab.${d.tab}`, d.group); render(); return; }
|
||||||
|
|
|
||||||
|
|
@ -1448,7 +1448,29 @@ class PrayerTest(unittest.TestCase):
|
||||||
self.assertEqual(p["pp"], 10)
|
self.assertEqual(p["pp"], 10)
|
||||||
self.assertEqual(p["xp"]["prayer"], game.XP_TABLE[1] + 20)
|
self.assertEqual(p["xp"]["prayer"], game.XP_TABLE[1] + 20)
|
||||||
world["city"]["buildings"]["temple"]["level"] = 2
|
world["city"]["buildings"]["temple"]["level"] = 2
|
||||||
self.assertEqual(game.bone_points(world, game.ACTION_BY_ID["bury_bones"]), 4)
|
self.assertEqual(game.bone_points(world, game.ACTION_BY_ID["bury_bones"]), 3)
|
||||||
|
|
||||||
|
def test_fight_bones_bury_on_the_spot(self):
|
||||||
|
world, p = self.priest(level=10)
|
||||||
|
world["city"]["buildings"]["temple"]["level"] = 2
|
||||||
|
p["potions"]["prayer"] = {"item": "prayer_potion_2", "charges": 50}
|
||||||
|
summary = game.empty_summary()
|
||||||
|
kept = game.bury_on_the_spot(world, p, {"bones": 2, "big_bones": 1, "hide": 1}, T0, summary)
|
||||||
|
self.assertEqual(kept, {"big_bones": 1, "hide": 1}) # big bones need prayer 15
|
||||||
|
self.assertEqual(p["pp"], 2 * 3 * 1.5)
|
||||||
|
self.assertEqual(p["potions"]["prayer"]["charges"], 48)
|
||||||
|
self.assertEqual(summary["xp"]["prayer"], 2 * game.ACTION_BY_ID["bury_bones"]["xp"] * game.SPOT_BURY_XP)
|
||||||
|
p["bury"] = False
|
||||||
|
self.assertEqual(game.bury_on_the_spot(world, p, {"bones": 2}, T0, summary), {"bones": 2})
|
||||||
|
|
||||||
|
def test_won_fights_bury_their_bones(self):
|
||||||
|
world, p = self.priest(level=10)
|
||||||
|
p["bank"] = {"bread": 200}
|
||||||
|
game.start_action(world, p, "fight_wolves", T0)
|
||||||
|
summary = game.process_player(world, p, T0 + 3600, random.Random(1))
|
||||||
|
self.assertGreater(summary["wins"], 0)
|
||||||
|
self.assertNotIn("bones", p["bank"])
|
||||||
|
self.assertGreaterEqual(summary["pp_gained"], 2 * summary["wins"])
|
||||||
|
|
||||||
def test_choosing_prayers(self):
|
def test_choosing_prayers(self):
|
||||||
world, p = self.priest(level=10)
|
world, p = self.priest(level=10)
|
||||||
|
|
@ -1461,17 +1483,17 @@ class PrayerTest(unittest.TestCase):
|
||||||
scouts = game.ACTION_BY_ID["fight_scouts"]
|
scouts = game.ACTION_BY_ID["fight_scouts"]
|
||||||
plain = game.fight_odds(p, scouts)["damage"]
|
plain = game.fight_odds(p, scouts)["damage"]
|
||||||
game.set_prayers(p, ["thick_skin", "burst_of_strength"])
|
game.set_prayers(p, ["thick_skin", "burst_of_strength"])
|
||||||
p["pp"] = 4
|
p["pp"], p["bury"] = 8, False
|
||||||
blessed = game.blessing(p)
|
blessed = game.blessing(p)
|
||||||
self.assertEqual(blessed["cost"], 2)
|
self.assertEqual(blessed["cost"], 4)
|
||||||
self.assertLess(game.fight_odds(p, scouts)["damage"], plain * 0.9)
|
self.assertLess(game.fight_odds(p, scouts)["damage"], plain * 0.9)
|
||||||
p["bank"] = {"bread": 200}
|
p["bank"] = {"bread": 200}
|
||||||
game.start_action(world, p, "fight_scouts", T0)
|
game.start_action(world, p, "fight_scouts", T0)
|
||||||
summary = game.process_player(world, p, T0 + 600, random.Random(1))
|
summary = game.process_player(world, p, T0 + 600, random.Random(1))
|
||||||
self.assertEqual(p["pp"], 0)
|
self.assertEqual(p["pp"], 0)
|
||||||
self.assertEqual(summary["pp_spent"], 4)
|
self.assertEqual(summary["pp_spent"], 8)
|
||||||
self.assertTrue(summary["prayer_out"])
|
self.assertTrue(summary["prayer_out"])
|
||||||
self.assertEqual(p["xp"]["prayer"], game.XP_TABLE[10] + 4 * game.PRAYER_XP_PER_POINT)
|
self.assertEqual(p["xp"]["prayer"], game.XP_TABLE[10] + 8 * game.PRAYER_XP_PER_POINT)
|
||||||
|
|
||||||
def test_second_wind_saves_one_knockout(self):
|
def test_second_wind_saves_one_knockout(self):
|
||||||
world, p = self.priest(level=40, combat=10)
|
world, p = self.priest(level=40, combat=10)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue