summaryrefslogtreecommitdiff
path: root/rules.js
diff options
context:
space:
mode:
Diffstat (limited to 'rules.js')
-rw-r--r--rules.js273
1 files changed, 259 insertions, 14 deletions
diff --git a/rules.js b/rules.js
index 2c90984..cc4ad9e 100644
--- a/rules.js
+++ b/rules.js
@@ -49,6 +49,10 @@ const last_province = S_TAMILAKAM
const faction_name = [ "Delhi Sultanate", "Bahmani Kingdom", "Vijayanagara Empire", "Mongol Invaders" ]
const faction_acronyms = [ "ds", "bk", "ve", "mi" ]
+const AD = [ "0", '\u2776', '\u2777', '\u2778', '\u2779', '\u277A', '\u277B' ]
+const DD = [ "0", '\u2460', '\u2461', '\u2462', '\u2463', '\u2464', '\u2465' ]
+
+
exports.scenarios = [ "Standard", "Solo" ]
exports.roles = function (scenario, _options) {
@@ -107,6 +111,7 @@ exports.view = function (state, role) {
rebel: game.rebel,
order: game.order,
who: {},
+ dice: game.dice,
}
if (game.result) {
@@ -215,6 +220,7 @@ exports.setup = function (seed, scenario, _options) {
inf_shift: null,
decree: null,
vm: null,
+ dice: [0, 0, 0, 0, 0, 0]
}
if (scenario === "Solo")
@@ -465,6 +471,7 @@ function goto_rebel() {
function goto_tax() {
init_decree("Tax")
+ game.decree.count = 1
game.state = "tax"
}
@@ -536,6 +543,7 @@ states.main_phase = {
view.actions.end_of_turn = 1
}
},
+ attack: goto_attack,
build: goto_build,
campaign: goto_campaign,
collect: goto_collect,
@@ -761,7 +769,7 @@ states.strategic_assistance = {
states.tax = {
prompt() {
- if (game.decree.n === 1) {
+ if (game.decree.count === 1) {
view.prompt = `Tax: Collect ${tax_count()} from Controlled Prosperity and Temples.`
gen_action_resources(VE)
} else {
@@ -774,7 +782,7 @@ states.tax = {
let t = tax_count()
add_resources(game.current, t)
logi_resources(VE, t)
- game.decree.n = 0
+ game.decree.count = 0
},
end_tax: end_decree
}
@@ -880,11 +888,202 @@ function end_decree() {
/* SHARED COMMANDS */
-function can_attack() {}
+function can_attack() {
+ for (let s = first_space; s <= last_space; ++s)
+ if (can_attack_in_space(s))
+ return true
+ return false
+}
-function can_attack_in_space(s) {}
+function can_attack_in_space(s) {
+ if (!has_valid_attackers(s, game.current))
+ return false
-function goto_attack() {}
+ if (game.current === DS) {
+ if (
+ can_attack_rebel_in_space(s, BK) ||
+ can_attack_rebel_in_space(s, VE) ||
+ has_piece(s, MI, TROOPS)
+ )
+ return true
+ } else if (game.current === BK) {
+ if (count_faction_pieces(s, DS) > 0 || count_faction_pieces(s, VE) > 0)
+ return true
+ } else if (game.current === VE) {
+ if (count_faction_pieces(s, DS) > 0 || count_faction_pieces(s, BK) > 0)
+ return true
+ }
+ return false
+}
+
+function can_attack_rebel_in_space(s, faction) {
+ if (
+ count_pieces(s, faction, DISC) === 1 &&
+ count_faction_pieces(s, faction) === 1
+ )
+ return true
+
+ if (has_rebel(s, faction))
+ return true
+
+ return false
+}
+
+function goto_attack() {
+ init_command("Attack")
+ game.cmd.attacker = game.current
+ game.state = "attack"
+}
+
+function goto_attack_select() {
+ game.cmd.target = [0, 0, 0, 0]
+ if (game.current === DS) {
+ game.cmd.target[BK] += can_attack_rebel_in_space(game.cmd.where, BK)
+ game.cmd.target[VE] += can_attack_rebel_in_space(game.cmd.where, VE)
+ game.cmd.target[MI] += has_piece(game.cmd.where, MI, TROOPS)
+ } else if (game.current === BK) {
+ game.cmd.target[DS] += count_faction_pieces(game.cmd.where, DS) > 0
+ game.cmd.target[VE] += count_faction_pieces(game.cmd.where, VE) > 0
+ } else if (game.current === VE) {
+ game.cmd.target[DS] += count_faction_pieces(game.cmd.where, DS) > 0
+ game.cmd.target[BK] += count_faction_pieces(game.cmd.where, BK) > 0
+ }
+
+ 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"
+ } else {
+ game.state = "attack_select"
+ }
+}
+
+function roll_attack(faction_d) {
+ for (let d = 0; d < 6; ++d)
+ game.dice[d] = random(6) + 1
+
+ if (faction_d === BK && has_piece(game.cmd.where, BK, DISC))
+ 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)
+
+ let is_attacker = (game.current === game.cmd.attacker)
+ let is_a_die = (d < 4)
+
+ if (is_a_die && is_attacker) {
+ charge_die(d)
+ } else if (!is_a_die && is_attacker) {
+ screen_die(d)
+ } else if (is_a_die && !is_attacker) {
+ screen_die(d)
+ } else if (!is_a_die && !is_attacker) {
+ charge_die[d]
+ }
+}
+
+function charge_die(d) {
+ if (d < 4) {
+ logi(`.ad ${AD[game.dice[d]]} \u27f6 ${AD[game.dice[d]-1]} charged`)
+ } else {
+ logi(`.dd ${DD[game.dice[d]]} \u27f6 ${DD[game.dice[d]-1]} charged`)
+ }
+ game.dice[d] -= 1
+}
+
+function screen_die(d) {
+ if (d < 4) {
+ logi(`.ad ${AD[game.dice[d]]} screened`)
+ } else {
+ logi(`.dd ${DD[game.dice[d]]} screened`)
+ }
+ game.dice[d] = 0
+}
+
+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()) {
+ for (let s = first_space; s <= last_space; ++s) {
+ if (!is_selected_cmd_space(s) && can_attack_in_space(s))
+ gen_action_space(s)
+ }
+ }
+ },
+ space(s) {
+ game.cmd.where = s
+ log_space(game.cmd.where, "Attack")
+ goto_attack_select()
+ }
+}
+
+states.attack_select = {
+ prompt() {
+ view.prompt = "Attack: Choose a Faction to attack"
+ }
+}
+
+states.attack_space = {
+ prompt() {
+ view.prompt = "Attack: "
+
+ view.actions.roll = 1
+ },
+ roll() {
+ 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()
+
+ goto_attack_cavalry()
+ }
+}
+
+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
+
+ let curr_die = [0, 1, 2, 3, 4, 5]
+ // TODO: restrict range for MI player
+
+ if (has_cavalry(game.current))
+ for (let d of curr_die)
+ if (game.dice[d] > 1)
+ gen_action_die(d)
+
+ view.actions.next = 1
+ },
+ die(d) {
+ if (!game.cmd.cavalry) {
+ log(`${faction_name[game.current]} is using Cavalry.`)
+ game.cmd.cavalry = true
+ }
+
+ attack_use_cavalry(d)
+ },
+ next() {
+
+ }
+}
/* DELHI SULTANATE COMMANDS */
@@ -1105,6 +1304,7 @@ function goto_migrate_space() {
}
states.migrate = {
+ // TODO: Check Rebel status after migration
prompt() {
view.prompt = "Migrate: Select a Province as the Migrate destination."
@@ -1305,13 +1505,13 @@ function collect_count() {
function goto_collect() {
init_decree("Collect")
- game.decree.n = 1
+ game.decree.count = 1
game.state = "collect"
}
states.collect = {
prompt() {
- if (game.decree.n > 0) {
+ if (game.decree.count > 0) {
view.prompt = `Collect Tribute: Collect ${collect_count()} from half the Tributaries prosperity`
gen_action_resources(DS)
} else {
@@ -1323,7 +1523,7 @@ states.collect = {
let c = collect_count()
add_resources(DS, c)
logi_resources(DS, c)
- game.decree.n = 0
+ game.decree.count = 0
goto_cavalry(2, "collect")
},
end_collect: end_decree,
@@ -1444,7 +1644,7 @@ function can_build_in_space(s) {
function goto_build() {
init_decree("Build")
- game.decree.n = 1
+ game.decree.count = 1
game.state = "build"
}
@@ -1455,7 +1655,7 @@ states.build = {
else if (game.current === VE)
view.prompt = "Build: Select a Province with a Raja."
- if (game.decree.n === 1) {
+ if (game.decree.count === 1) {
for (let s = first_space; s <= last_space; ++s) {
if (can_build_in_space(s))
gen_action_space(s)
@@ -1473,7 +1673,7 @@ states.build = {
place_piece(p, s)
log_space(s, "Build")
pop_summary()
- game.decree.n = 0
+ game.decree.count = 0
},
end_build: end_decree,
}
@@ -1658,12 +1858,13 @@ function trade_count() {
function goto_trade() {
init_decree("Trade")
+ game.decree.count = 1
game.state = "trade"
}
states.trade = {
prompt() {
- if (game.decree.n === 1) {
+ if (game.decree.count === 1) {
view.prompt = `Trade: Collect ${trade_count()} from Provinces with your presence.`
gen_action_resources(BK)
} else {
@@ -1675,7 +1876,7 @@ states.trade = {
let t = trade_count()
add_resources(game.current, t)
logi_resources(BK, t)
- game.decree.n = 0
+ game.decree.count = 0
goto_cavalry(trade_cavalry_count(), "trade")
},
end_trade: end_decree,
@@ -1760,6 +1961,16 @@ function remove_tributary(s) {
update_control()
}
+function has_rebel(s, faction) {
+ let p0 = first_piece[faction][ELITE]
+ let p1 = last_piece[faction][ELITE]
+ for (let p = p0; p <= p1; ++p)
+ if (piece_space(p) === s)
+ if (is_rebel(p))
+ return true
+ return false
+}
+
function is_rebel(p) {
let faction = piece_faction(p)
let piece_index = p - first_piece[faction][ELITE]
@@ -1890,6 +2101,20 @@ function has_unmoved_piece(s, faction) {
return unmoved
}
+function has_valid_attackers(s, faction) {
+ let valid_attacker = false
+ for_each_movable(faction, p => {
+ if (piece_space(p) === s)
+ valid_attacker = true
+ if (piece_space(p) === s || (has_piece(piece_space(p), faction, DISC) && SPACES[s].adjacent.includes(piece_space(p))))
+ if (!game.cmd.pieces || game.cmd.pieces.length === 0)
+ valid_attacker = true
+ else if (!set_has(game.cmd.pieces, p))
+ valid_attacker = true
+ })
+ return valid_attacker
+}
+
function gen_place_piece(faction, type) {
for_each_piece(faction, type, p => {
if (piece_space(p) === AVAILABLE) {
@@ -2004,6 +2229,22 @@ function trade_cavalry_count() {
return 3;
}
+function find_cavalry(faction) {
+ for (let c = 0; c <= LAST_CAVALRY; ++c)
+ if (game.cavalry[c] === faction)
+ return c
+ return -1
+}
+
+function has_cavalry(faction) {
+ return find_cavalry(faction) != -1
+}
+
+function use_cavalry(faction) {
+ let c = find_cavalry(faction)
+ game.cavalry[c] = AVAILABLE
+}
+
/* INFLUENCE */
function add_influence(faction) {
@@ -2127,6 +2368,10 @@ function gen_action(action, argument) {
set_add(view.actions[action], argument)
}
+function gen_action_die(d) {
+ gen_action("die", d)
+}
+
function gen_action_influence(faction) {
gen_action("inf", faction)
}
@@ -2614,7 +2859,7 @@ function for_each_movable(faction, f) {
if (faction === BK)
for_each_piece(BK, ELITE, f)
else if (faction === VE)
- for_each_piece(BK, ELITE, f)
+ for_each_piece(VE, ELITE, f)
else if (faction === DS) {
for_each_piece(DS, TROOPS, f)
for_each_piece(DS, ELITE, f)