summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2021-06-22 14:01:09 +0200
committerTor Andersson <tor@ccxvii.net>2022-11-16 19:19:38 +0100
commit26220db4d462922e8ab90a91332f43ba63cf695e (patch)
tree0c644dac01b2990ebd8da90ca2d0fdde6e28dbc4
parente7f7b3ca0017a9cd12078d4c842685f5e60f8e84 (diff)
downloadcrusader-rex-26220db4d462922e8ab90a91332f43ba63cf695e.tar.gz
crusader: Show/hide blocks in battle properly.
-rw-r--r--SIEGE254
-rw-r--r--play.html3
-rw-r--r--rules.js7
-rw-r--r--ui.js38
4 files changed, 279 insertions, 23 deletions
diff --git a/SIEGE b/SIEGE
new file mode 100644
index 0000000..8bff6cc
--- /dev/null
+++ b/SIEGE
@@ -0,0 +1,254 @@
+== SIEGE AND BATTLE PROCEDURE ==
+
+* COMBAT DEPLOYMENT
+
+if not siege then
+ defender may withdraw into castle.
+ if field is empty and no reserves in queue then
+ attacker may regroup.
+ goto combat round 1.
+ end
+end
+
+* COMBAT ROUND 1 TO 3
+
+if round 2 then
+ primary reserves arrive.
+end
+
+if round 3 then
+ secondary reserves arrive.
+end
+
+if besieged reserves arrive then
+ withdraw all storming units to field.
+ besieging is defender.
+ besieged is attacker.
+end
+
+if field is contested then
+ besieged may sally into field.
+ battle with all units in field.
+ if victorious then
+ victor may regroup.
+ if not siege then
+ end battle.
+ end
+ end
+
+else if currently storming or attacker declares storming then
+ besieging is attacker
+ besieged is defender
+ besieging may add blocks to storm.
+ battle with all units in castle.
+ if besieging is victorious then
+ besieging may regroup.
+ end battle.
+ end
+
+else if defender declares sallying then
+ besieging is defender.
+ besieged is attacker.
+ battle with all units in field.
+ if victorious then
+ victor may regroup.
+ if not siege then
+ end battle.
+ end
+ end
+
+else if no reserves in queue then
+ goto siege attrition.
+end
+
+if round 1 or round 2 then
+ goto next combat round.
+else
+ goto after battle retreat.
+end
+
+* AFTER BATTLE RETREAT
+
+withdraw all sallying units to castle.
+withdraw all storming units to field.
+
+if field is contested then
+ attacker must retreat
+ defender may regroup
+end
+
+if siege then
+ goto siege attrition.
+else
+ end battle.
+end
+
+* SIEGE ATTRITION
+
+roll and apply attrition.
+if castle falls then
+ besieging may regroup
+end
+
+end battle.
+
+== BATTLE UI SCREENS ==
+
+area: "Reserves"
+area: "Field"
+area: "Withdraw Castle" -- defender
+area: "Storming Castle" -- attacker
+ -> "Castle"
+
+* Combat Deployment
+ defender main force can choose to 'withdraw'
+* Declare Storming
+ besieging main force can choose to 'storm'
+* Declare Sally
+ besieged in castle can choose to 'sally'
+* Battle round in castle
+ show field as reserves
+
+With big screen:
+
+ enemy reserves
+ enemy castle (optional)
+ enemy field
+ my field
+ my castle (optional)
+ my reserves
+
+
+=============
+
+1) New fight!
+
+Defender deploys (main forces only) in castle and/or field. -- see example on page 5
+
+// -- ERROR: reserve blocks moving into same area? --
+// If all withdraw and no reinforcements are coming, attacker may regroup.
+// Regroup into other existing siege -- arrive as reinforcements.
+// If any attacker blocks stay, goto existing siege.
+
+If any defenders stay, goto field battle.
+Else goto siege.
+
+2) Field battle!
+
+Defender may withdraw into castle as combat action.
+
+If defender is eliminated and there are blocks in the castle, goto existing siege.
+
+Else regroup.
+
+3) Existing siege!
+
+Attacker declares storm?
+ goto storm round
+
+Defender declares sally?
+ goto sally round
+
+---
+
+Combat Deployment
+ Defender may withdraw into castle if new battle.
+
+Combat Round 1
+ If field has units
+ -> defender declare sally (if possible)
+ -> battle round in field.
+ Else attacker declare storm?
+ -> battle round in castle
+ Else defender declare sally?
+ -> besieged becomes attacker
+ -> battle round in field
+ Else if no reinforcements on the way
+ -> skip to siege attrition
+
+Combat Round 2
+ Reserves arrive.
+ Besieged becomes attacker if relief forces arrive.
+ If field is empty
+ -> attacker may regroup some blocks (see 6.7 regroups note)
+ Else if field has units
+ -> defender declare sally (if possible)
+ -> battle round in field.
+ Else if storm ongoing?
+ -> attacker declare more storming units
+ -> battle round in castle
+ Else attacker declare storm?
+ -> battle round in castle
+ Else defender declare sally?
+ -> besieged becomes attacker
+ -> battle round in field
+ Else if no reinforcements on the way
+ -> skip to siege attrition
+ Same as Round 1.
+
+Combat Round 3
+ Same as Round 2.
+
+>>> Battle round in field
+ if field is empty
+ if attacker is in field
+ attacker may regroup
+ if attacker is besieging and leaves some
+ proceed to next combat round
+ else
+ end combat
+ end
+ else
+ defender may regroup
+ end combat
+ end
+ end
+
+Retreat Round
+ All sallying withdraw.
+ All storming withdraw.
+ If field units:
+ Attacker/besieging must retreat
+
+Siege Attrition
+ Roll for attrition.
+ If defender is eliminated, attacker may regroup.
+
+---
+
+6.56 timing
+
+ new siege:
+ 2 frank in town
+ 3 saracen attack main road
+ 1 saracen attack secondary road
+ 2 frank reinforce main
+ 1 frank reinforce secondary
+
+
+ round 1: 2 frank vs 3 saracen
+ round 2: 2+2 frank vs 3+1 saracen
+ round 3: 2+2+1 frank vs 3+1 saracen
+
+ old siege:
+ 2 p1 in castle
+ 2 p2 in field
+ 1 p1 attack main road (relief)
+ 1 p1 attack second road
+ 1 p2 reinforce main road
+ 1 p2 reinforce second road
+
+ round 1: 2+1 p1 vs 2 p2
+ round 2: 2+1 p1 vs 2+1 p2
+ round 3: 2+1+1 p1 vs 2+1+1 p2
+
+ old siege #2:
+ 2 p1 in field
+ 2 p2 in castle
+ p1 pass
+ 1 p2 reinforce main road (relief)
+ 1 p2 reinforce second road
+
+ round 1: 2 p1 vs 2 p2 -or- 2 p1 vs 2+1 p2?
+ -- I believe the rules clarification missed this case --
+
diff --git a/play.html b/play.html
index 18c1dec..176706c 100644
--- a/play.html
+++ b/play.html
@@ -237,8 +237,9 @@ body.shift .block.known:hover {
#FA, #FB, #FC, #FD, #FR, #EA, #EB, #EC, #ER { margin: 0px; padding: 5px; }
.battle .battle_menu { margin: 10px 5px; }
-#FC { min-height: 110px; }
+#FC { min-height: 120px; }
#EC { min-height: 80px; }
+#FF, #EF { min-height: 120px; }
#FC, #EC {
background-color: gray;
margin-left: auto;
diff --git a/rules.js b/rules.js
index 0ea4fb8..335cc1d 100644
--- a/rules.js
+++ b/rules.js
@@ -2148,6 +2148,9 @@ function resume_field_battle() {
return goto_regroup();
}
+ if (!is_contested_battle_field())
+ return next_combat_round();
+
game.state = 'field_battle';
pump_battle_step(is_field_attacker, is_field_defender);
}
@@ -2643,6 +2646,8 @@ function make_battle_view() {
sallying: game.sallying,
halfhit: game.halfhit,
flash: game.flash,
+ round: game.combat_round,
+ show_castle: game.storming.length > 0 && game.state != 'declare_storm',
};
battle.title = game.attacker[game.where] + " attack " + game.where;
@@ -2653,7 +2658,7 @@ function make_battle_view() {
function fill_cell(cell, owner, fn) {
for (let b in BLOCKS)
if (game.location[b] == game.where & block_owner(b) == owner && fn(b))
- cell.push([b, game.steps[b], game.moved[b]?1:0])
+ cell.push(b)
// cell.sort((a,b) => compare_block_initiative(a[0], b[0]));
}
diff --git a/ui.js b/ui.js
index b6125ad..7b73462 100644
--- a/ui.js
+++ b/ui.js
@@ -615,12 +615,12 @@ function update_cards() {
}
function update_battle() {
- function fill_cell(name, list, reserve) {
+ function fill_cell(name, list, show) {
let cell = document.getElementById(name);
ui.present.clear();
- for (let [block, steps, moved] of list) {
+ for (let block of list) {
ui.present.add(block);
// TODO: insert in correct order!
@@ -665,24 +665,20 @@ function update_battle() {
if (game.actions && game.actions.battle_treachery && game.actions.battle_treachery.includes(block))
ui.battle_menu[block].classList.add('treachery');
- update_steps(block, steps, ui.battle_block[block], false);
+ update_steps(block, game.steps[block], ui.battle_block[block], false);
if (block == game.battle.halfhit)
ui.battle_block[block].classList.add("halfhit");
else
ui.battle_block[block].classList.remove("halfhit");
- if (reserve)
- ui.battle_block[block].classList.add("secret");
+ if (show)
+ ui.battle_block[block].classList.add("known");
else
- ui.battle_block[block].classList.remove("secret");
- if (moved)
+ ui.battle_block[block].classList.remove("known");
+ if (game.moved[block])
ui.battle_block[block].classList.add("moved");
else
ui.battle_block[block].classList.remove("moved");
- if (reserve)
- ui.battle_block[block].classList.remove("known");
- else
- ui.battle_block[block].classList.add("known");
}
for (let b in BLOCKS) {
@@ -695,19 +691,19 @@ function update_battle() {
if (player == FRANKS) {
fill_cell("FR", game.battle.FR, true);
- fill_cell("FC", game.battle.FC, false);
- fill_cell("FF", game.battle.FF, false);
- fill_cell("EF", game.battle.SF, false);
- fill_cell("EC", game.battle.SC, false);
- fill_cell("ER", game.battle.SR, true);
+ fill_cell("FC", game.battle.FC, true);
+ fill_cell("FF", game.battle.FF, true);
+ fill_cell("EF", game.battle.SF, game.battle.round > 0);
+ fill_cell("EC", game.battle.SC, game.battle.show_castle);
+ fill_cell("ER", game.battle.SR, false);
document.getElementById("FC").className = "c" + game.battle.FCS;
document.getElementById("EC").className = "c" + game.battle.SCS;
} else {
- fill_cell("ER", game.battle.FR, true);
- fill_cell("EC", game.battle.FC, false);
- fill_cell("EF", game.battle.FF, false);
- fill_cell("FF", game.battle.SF, false);
- fill_cell("FC", game.battle.SC, false);
+ fill_cell("ER", game.battle.FR, false);
+ fill_cell("EC", game.battle.FC, game.battle.show_castle);
+ fill_cell("EF", game.battle.FF, game.battle.round > 0);
+ fill_cell("FF", game.battle.SF, true);
+ fill_cell("FC", game.battle.SC, true);
fill_cell("FR", game.battle.SR, true);
document.getElementById("EC").className = "c" + game.battle.FCS;
document.getElementById("FC").className = "c" + game.battle.SCS;