summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--play.css2
-rw-r--r--rules.js257
2 files changed, 230 insertions, 29 deletions
diff --git a/play.css b/play.css
index 41a2382..2a25835 100644
--- a/play.css
+++ b/play.css
@@ -137,6 +137,8 @@ main { background-color: #777; }
#log .italic { font-style: italic; }
#log div { padding-left: 20px; text-indent: -12px; }
#log div.indent { padding-left: 32px; text-indent: -12px; }
+#log .h1 { border-bottom: 2px solid #444; border-top: 2px solid #444; }
+#log .h2 { border-bottom: 1px solid #444; border-top: 1px solid #444; }
#log .adice {
font-size: 14px;
diff --git a/rules.js b/rules.js
index cc4ad9e..4d7fdbb 100644
--- a/rules.js
+++ b/rules.js
@@ -342,6 +342,7 @@ function goto_eligible() {
limited: 0,
free: 0,
spaces: [],
+ pieces: [],
where: -1,
pass: 1
}
@@ -412,7 +413,7 @@ function goto_cavalry(n, next) {
}
function goto_compromising_gifts() {
- if (game.inf[game.cmd.who] === 0)
+ if (game.inf[game.current] === 0)
end_card()
else
game.state = "compromising_gifts"
@@ -932,10 +933,12 @@ function can_attack_rebel_in_space(s, faction) {
function goto_attack() {
init_command("Attack")
game.cmd.attacker = game.current
+ game.cmd.support_space = null
game.state = "attack"
}
function goto_attack_select() {
+ game.cmd.selected = []
game.cmd.target = [0, 0, 0, 0]
if (game.current === DS) {
game.cmd.target[BK] += can_attack_rebel_in_space(game.cmd.where, BK)
@@ -952,7 +955,7 @@ function goto_attack_select() {
let n = game.cmd.target.reduce((a, c) => a + c, 0);
if (n === 1) {
game.cmd.target = game.cmd.target.indexOf(1)
- game.state = "attack_space"
+ goto_attack_space()
} else {
game.state = "attack_select"
}
@@ -966,11 +969,6 @@ function roll_attack(faction_d) {
game.dice[3] = 0
}
-function goto_attack_cavalry() {
- game.cmd.clog = false
- game.state = "attack_cavalry"
-}
-
function attack_use_cavalry(d) {
use_cavalry(game.current)
@@ -1008,20 +1006,25 @@ function screen_die(d) {
states.attack = {
prompt() {
- if (game.current === DS)
- view.prompt = "Attack: Select Spaces with Rebels or Mongol Invaders."
- else
- view.prompt = "Attack: Select Provinces with enemy pieces."
-
if (can_select_cmd_space(1) && can_attack()) {
+ if (game.current === DS)
+ view.prompt = "Attack: Select Spaces with Rebels or Mongol Invaders."
+ else
+ view.prompt = "Attack: Select Provinces with enemy pieces."
+
for (let s = first_space; s <= last_space; ++s) {
if (!is_selected_cmd_space(s) && can_attack_in_space(s))
gen_action_space(s)
}
+ } else {
+ view.prompt = "Attack: Done."
}
},
space(s) {
+ push_undo()
game.cmd.where = s
+ select_cmd_space(game.cmd.where, 1)
+ set_add(game.cmd.spaces, game.cmd.where)
log_space(game.cmd.where, "Attack")
goto_attack_select()
}
@@ -1029,38 +1032,136 @@ states.attack = {
states.attack_select = {
prompt() {
- view.prompt = "Attack: Choose a Faction to attack"
+ view.prompt = "Attack: Choose a Faction to attack."
+ for (let [f, t] of game.cmd.target.entries())
+ if (t != 0)
+ gen_faction_in_space(game.cmd.where, f)
+
+ },
+ piece(p) {
+ let f = piece_faction(p)
+ game.cmd.target = f
+ goto_attack_space()
+ }
+}
+
+function goto_attack_space() {
+ game.cmd.n_units = [0, 0]
+
+ for_each_movable(game.cmd.target, p => {
+ if (piece_space(p) === game.cmd.where) {
+ set_add(game.cmd.selected, p)
+ set_add(game.cmd.pieces, p)
+ game.cmd.n_units[1] += 1
+ if (game.cmd.target === BK || game.cmd.target === VE)
+ to_rebel(p)
+ }
+ })
+ for_each_piece(game.cmd.target, DISC, p => {
+ if (piece_space(p) === game.cmd.where)
+ set_add(game.cmd.selected, p)
+ })
+ for_each_movable(game.cmd.attacker, p => {
+ if (piece_space(p) === game.cmd.where) {
+ set_add(game.cmd.selected, p)
+ set_add(game.cmd.pieces, p)
+ game.cmd.n_units[0] += 1
+ }
+ })
+ game.cmd.n_adj = (game.current === VE) ? 1 : 2
+
+ if (has_valid_support_attackers(game.cmd.where, game.cmd.attacker))
+ game.state = "attack_adjacent_support"
+ else
+ game.state = "attack_space"
+}
+
+states.attack_adjacent_support = {
+ prompt() {
+ view.who = game.cmd.selected
+
+ if (game.current === DS)
+ view.prompt = "Attack: Add up to two Units from adjacent Space with a Qasbah."
+ else if (game.current === BK)
+ view.prompt = "Attack: Add up to two Amirs from adjacent Province with a Fort."
+ else if (game.current === VE)
+ view.prompt = "Attack: Add up to one Raja from adjacent Province with a Temple."
+
+ if (game.cmd.support_space == null) {
+ for (let s = first_space; s <= last_space; ++s)
+ if (can_support_from(s, game.cmd.attacker))
+ gen_action_space(s)
+ } else {
+ if (game.cmd.n_adj > 0)
+ for_each_movable(game.cmd.attacker, p => {
+ if (
+ piece_space(p) === game.cmd.support_space &&
+ !set_has(game.cmd.selected, p) &&
+ !set_has(game.cmd.pieces, p)
+ )
+ gen_action_piece(p)
+ })
+ }
+
+ if (game.cmd.n_units[0] > 0)
+ view.actions.next = 1
+ },
+ space(s) {
+ game.cmd.support_space = s
+ },
+ piece(p) {
+ set_add(game.cmd.selected, p)
+ set_add(game.cmd.pieces, p)
+ game.cmd.n_adj -= 1
+ game.cmd.n_units[0] += 1
+
+ },
+ next() {
+ game.state = "attack_space"
}
}
states.attack_space = {
prompt() {
- view.prompt = "Attack: "
+ view.prompt = "Attack: Roll the die to attack."
+ view.who = game.cmd.selected
view.actions.roll = 1
},
roll() {
+ // clear_undo() TODO: remove for prd
roll_attack()
log(">.ad " + game.dice.slice(0,4).map(d => AD[d]).join(" "))
log(">.dd " + game.dice.slice(4).map(d => DD[d]).join(" "))
log_br()
+ game.cmd.step = 0
goto_attack_cavalry()
}
}
+function goto_attack_cavalry() {
+ if (game.cmd.step === 0) {
+ game.current = game.cmd.attacker
+ game.state = "attack_cavalry"
+ } else if (game.cmd.step === 1) {
+ game.current = game.cmd.target
+ game.state = "attack_cavalry"
+ } else {
+ game.cmd.a_hit = game.dice.slice(0,4).filter(d => d > 0 && d <= game.cmd.n_units[0]).length
+ game.cmd.d_hit = game.dice.slice(4).filter(d => d > 0 && d <= game.cmd.n_units[1]).length
+ game.cmd.victor = get_attack_victor()
+ log_br()
+ log(`${faction_name[game.cmd.attacker]} scores ${game.cmd.a_hit} hits.`)
+ log(`${faction_name[game.cmd.target]} scores ${game.cmd.d_hit} hits.`)
+ goto_attack_casualties("target")
+ }
+}
+
states.attack_cavalry = {
prompt() {
view.prompt = "Attack: Use cavalry to..."
-
- // game.cmd.attacker
- // game.cmd.target
- // game.current
- //
-
- // STEP ?
- // step 1 - attacker cavalry
- // step 2 - defender calvary
+ view.who = game.cmd.selected
let curr_die = [0, 1, 2, 3, 4, 5]
// TODO: restrict range for MI player
@@ -1081,10 +1182,70 @@ states.attack_cavalry = {
attack_use_cavalry(d)
},
next() {
+ game.cmd.step += 1
+ goto_attack_cavalry()
+ }
+}
+
+function get_attack_victor() {
+ if (game.cmd.a_hit > game.cmd.d_hit)
+ return game.cmd.attacker
+ else if (game.cmd.a_hit < game.cmd.d_hit)
+ return game.cmd.target
+ else
+ return -1
+}
+function goto_attack_casualties(step) {
+ if (step === "target") {
+ game.current = game.cmd.target
+ game.cmd.count = game.cmd.a_hit
+ game.state = "attack_casualties"
+ } else if (step === "attacker") {
+ game.current = game.cmd.attacker
+ game.cmd.count = game.cmd.d_hit
+ game.state = "attack_casualties"
}
}
+states.attack_casualties = {
+ prompt() {
+
+ if (
+ game.cmd.count > 0 &&
+ game.cmd.selected.filter(p => piece_faction(p) === game.current).length > 0
+ ) {
+ view.prompt = `Attack: ${faction_name[game.current]} must remove ${game.cmd.count} pieces as casualties.`
+
+ for (let p of game.cmd.selected)
+ if (piece_faction(p) === game.current)
+ gen_action_piece(p)
+ } else {
+ view.prompt = "Attack: No more casualties to remove."
+ view.actions.next = 1
+ }
+
+ },
+ piece(p) {
+ remove_piece(p)
+ set_delete(game.cmd.selected, p)
+ game.cmd.count -= 1
+ },
+ next() {
+ if (game.current === game.cmd.target)
+ goto_attack_casualties("attacker")
+ else
+ goto_attack_resolution()
+ }
+}
+
+function goto_attack_resolution() {
+ if (is_rebel_faction(game.cmd.target) && is_rebel_faction(game.cmd.attacker))
+ console.log("Implement shift")
+ game.state = "attack"
+
+}
+
/* DELHI SULTANATE COMMANDS */
@@ -1956,6 +2117,16 @@ function is_faction_control(s, faction) {
return game.control[faction] & (1 << s)
}
+function is_rebel_faction(faction) {
+ if (faction === BK || faction === VE)
+ return true
+ return false
+}
+
+function is_rebel_faction_elite(p) {
+ return (piece_type(p) === ELITE && [BK, VE].includes(piece_faction(p)))
+}
+
function remove_tributary(s) {
game.tributary &= ~(1 << s)
update_control()
@@ -1978,9 +2149,11 @@ function is_rebel(p) {
}
function to_obedient(p) {
- let faction = piece_faction(p)
- let piece_index = p - first_piece[faction][ELITE]
- game.rebel[faction] &= ~(1 << piece_index)
+ if (is_rebel_faction_elite(p)) {
+ let faction = piece_faction(p)
+ let piece_index = p - first_piece[faction][ELITE]
+ game.rebel[faction] &= ~(1 << piece_index)
+ }
}
function to_obedient_space(s) {
@@ -2089,10 +2262,10 @@ function has_piece_faction(s, faction) {
return count_faction_pieces(s, faction) > 0
}
-function has_unmoved_piece(s, faction) {
+function has_unmoved_piece(space, faction) {
let unmoved = false
for_each_movable(faction, p => {
- if (piece_space(p) === s)
+ if (piece_space(p) === space)
if (!game.cmd.pieces || game.cmd.pieces.length === 0)
unmoved = true
else if (!set_has(game.cmd.pieces, p))
@@ -2115,6 +2288,23 @@ function has_valid_attackers(s, faction) {
return valid_attacker
}
+function can_support_from(s, faction) {
+ let valid_attacker = false
+ for_each_movable(faction, p => {
+ if (piece_space(p) === s && has_piece(s, faction, DISC))
+ valid_attacker = true
+ })
+ return valid_attacker
+}
+
+
+function has_valid_support_attackers(s, faction) {
+ for (let ss of SPACES[s].adjacent)
+ if (can_support_from(ss, faction))
+ return true
+ return false
+}
+
function gen_place_piece(faction, type) {
for_each_piece(faction, type, p => {
if (piece_space(p) === AVAILABLE) {
@@ -2144,6 +2334,7 @@ function place_piece(p, s) {
}
function remove_piece(p) {
+ to_obedient(p)
set_piece_space(p, AVAILABLE)
update_control()
}
@@ -2855,6 +3046,15 @@ function gen_piece_in_space(space, faction, type) {
})
}
+function gen_faction_in_space(space, faction) {
+ if (faction === BK || faction === VE || faction === DS) {
+ gen_piece_in_space(space, faction, ELITE)
+ gen_piece_in_space(space, faction, DISC)
+ }
+ if (faction === DS || faction === MI)
+ gen_piece_in_space(space, faction, TROOPS)
+}
+
function for_each_movable(faction, f) {
if (faction === BK)
for_each_piece(BK, ELITE, f)
@@ -2863,7 +3063,6 @@ function for_each_movable(faction, f) {
else if (faction === DS) {
for_each_piece(DS, TROOPS, f)
for_each_piece(DS, ELITE, f)
-
}
}