summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--land-and-freedom.css85
-rw-r--r--land-and-freedom.scss84
-rw-r--r--play.html21
-rw-r--r--play.js101
-rw-r--r--play.ts125
-rw-r--r--rules.js148
-rw-r--r--rules.ts173
-rw-r--r--types.d.ts22
8 files changed, 587 insertions, 172 deletions
diff --git a/land-and-freedom.css b/land-and-freedom.css
index 196eddb..5fff93b 100644
--- a/land-and-freedom.css
+++ b/land-and-freedom.css
@@ -35,6 +35,7 @@ main {
grid-row: 1;
display: flex;
flex-direction: column;
+ background: floralwhite;
}
#roles {
@@ -43,22 +44,22 @@ main {
}
#role_Anarchist {
- background-color: rgb(76, 70, 89);
+ background-color: rgb(93, 89, 106);
}
#role_Communist {
- background-color: rgb(255, 0, 0);
+ background-color: rgb(237, 36, 27);
}
#role_Moderate {
- background-color: rgb(126, 18, 80);
+ background-color: rgb(134, 44, 97);
}
.role {
- color: white;
+ color: floralwhite;
}
.role a {
- color: white;
+ color: floralwhite;
}
.panel {
@@ -80,7 +81,7 @@ main {
}
.panel_header {
- color: white;
+ color: floralwhite;
user-select: none;
font-weight: bold;
text-align: center;
@@ -93,15 +94,15 @@ main {
}
.panel_header[data-faction-id=a] {
- background-color: rgb(76, 70, 89);
+ background-color: rgb(93, 89, 106);
}
.panel_header[data-faction-id=c] {
- background-color: rgb(255, 0, 0);
+ background-color: rgb(237, 36, 27);
}
.panel_header[data-faction-id=m] {
- background-color: rgb(126, 18, 80);
+ background-color: rgb(134, 44, 97);
}
.front {
@@ -116,18 +117,30 @@ main {
border-radius: 20px;
}
+.contributions {
+ display: flex;
+ flex-direction: row;
+ gap: 2px;
+ margin-top: 15px;
+ height: 25px;
+}
+
.front .value {
font-weight: bold;
font-size: 30px;
margin-top: auto;
}
-.front[data-front-id=m] {
+#madrid_front {
width: 104px;
height: 114px;
border-radius: 23px;
}
+#madrid_front .contributions {
+ padding: 0px 2px;
+}
+
.card {
background-size: 100% 100%;
width: 198px;
@@ -585,26 +598,35 @@ main {
margin-top: 1px;
}
-.glory {
+.faction_token {
box-sizing: border-box;
+ background-size: 100% 100%;
+}
+
+#glory .faction_token {
position: absolute;
width: 34px;
height: 34px;
- background-size: 100% 100%;
border-radius: 4px;
}
-.glory[data-faction-id=a] {
+.contributions .faction_token {
+ width: 25px;
+ height: 25px;
+ border-radius: 4px;
+}
+
+.faction_token[data-faction-id=a] {
border: 1px #333 solid;
background-image: url("images/factions/anarchists.png");
}
-.glory[data-faction-id=c] {
+.faction_token[data-faction-id=c] {
border: 1px #333 solid;
background-image: url("images/factions/communitsts.png");
}
-.glory[data-faction-id=m] {
+.faction_token[data-faction-id=m] {
border: 1px #333 solid;
background-image: url("images/factions/moderates.png");
}
@@ -745,9 +767,38 @@ main {
}
#log .h1 {
- background-color: hsl(4, 40%, 73%);
+ background-color: rgb(233, 223, 200);
}
#log .h2 {
- background-color: hsl(250, 40%, 83%);
+ background-color: rgb(233, 223, 200);
+}
+
+#log .h2.anarchist {
+ background-color: rgb(93, 89, 106);
+ color: floralwhite;
+}
+
+#log .h2.communist {
+ background-color: rgb(237, 36, 27);
+ color: floralwhite;
+}
+
+#log .h2.moderate {
+ background-color: rgb(134, 44, 97);
+ color: floralwhite;
+}
+
+#log .h2.fascist {
+ background-color: rgb(183, 144, 105);
+}
+
+#log div.i {
+ padding-left: 32px;
+ text-indent: -12px;
+}
+
+#log div.ii {
+ padding-left: 44px;
+ text-indent: -12px;
}
diff --git a/land-and-freedom.scss b/land-and-freedom.scss
index 8b9636f..6385944 100644
--- a/land-and-freedom.scss
+++ b/land-and-freedom.scss
@@ -4,9 +4,11 @@
$selectable-color: white; // yellow;
$selected-color: yellow; //blue;
-$anarchist-color: rgb(76, 70, 89);
-$communist-color: rgb(255, 0, 0);
-$moderate-color: rgb(126, 18, 80);
+$anarchist-color: rgb(93, 89, 106);
+$communist-color: rgb(237, 36, 27);
+$moderate-color: rgb(134, 44, 97);
+$fascist-color: rgb(183, 144, 105);
+$log-text-background-color: rgb(233 223 200);
main {
// background-color: rgb(213, 196, 131);
@@ -57,6 +59,7 @@ main {
grid-row: 1;
display: flex;
flex-direction: column;
+ background: floralwhite;
}
#roles {
@@ -90,10 +93,10 @@ main {
}
.role {
- color: white;
+ color:floralwhite;
a {
- color: white;
+ color:floralwhite;
}
}
@@ -117,7 +120,7 @@ main {
}
.panel_header {
- color: white;
+ color: floralwhite;
user-select: none;
font-weight: bold;
text-align: center;
@@ -165,18 +168,39 @@ main {
// opacity: 0.5;
}
+.contributions {
+ display: flex;
+ flex-direction: row;
+ gap: 2px;
+ // width: 100%;
+ margin-top: 15px;
+ // background-color: yellow;
+ // opacity: 0.5;
+ height: 25px;
+}
+
.front .value {
font-weight: bold;
font-size: 30px;
margin-top: auto;
}
-.front[data-front-id='m'] {
+#madrid_front {
width: 104px;
height: 114px;
border-radius: 23px;
}
+#madrid_front .contributions {
+ padding: 0px 2px;
+}
+
+// .front[data-front-id='m'] {
+// width: 104px;
+// height: 114px;
+// border-radius: 23px;
+// }
+
.card {
background-size: 100% 100%;
// width: 275px;
@@ -212,29 +236,38 @@ main {
margin-top: 1px;
}
-.glory {
+.faction_token {
box-sizing: border-box;
- position: absolute;
// background-color: yellow;
// opacity: 0.5;
- width: 34px;
- height: 34px;
background-size: 100% 100%;
// box-shadow: 0 0 0 1px #333;
+}
+
+#glory .faction_token {
+ position: absolute;
+ width: 34px;
+ height: 34px;
border-radius: 4px;
}
-.glory[data-faction-id='a'] {
+.contributions .faction_token {
+ width: 25px;
+ height: 25px;
+ border-radius: 4px;
+}
+
+.faction_token[data-faction-id='a'] {
border: 1px #333 solid;
background-image: url('images/factions/anarchists.png');
}
-.glory[data-faction-id='c'] {
+.faction_token[data-faction-id='c'] {
border: 1px #333 solid;
background-image: url('images/factions/communitsts.png');
}
-.glory[data-faction-id='m'] {
+.faction_token[data-faction-id='m'] {
border: 1px #333 solid;
background-image: url('images/factions/moderates.png');
}
@@ -327,8 +360,27 @@ main {
text-align: center;
}
#log .h1 {
- background-color: hsl(4, 40%, 73%);
+ // background-color: hsl(4, 40%, 73%);
+ background-color: $log-text-background-color;
}
#log .h2 {
- background-color: hsl(250, 40%, 83%);
+ // background-color: hsl(250, 40%, 83%);
+ background-color: $log-text-background-color;
+}
+#log .h2.anarchist {
+ background-color: $anarchist-color;
+ color:floralwhite;
+}
+#log .h2.communist {
+ background-color: $communist-color;
+ color:floralwhite;
+}
+#log .h2.moderate {
+ background-color: $moderate-color;
+ color:floralwhite;
+}
+#log .h2.fascist {
+ background-color: $fascist-color;
}
+#log div.i { padding-left: 32px; text-indent: -12px; }
+#log div.ii { padding-left: 44px; text-indent: -12px; } \ No newline at end of file
diff --git a/play.html b/play.html
index fffbbca..f7a6189 100644
--- a/play.html
+++ b/play.html
@@ -33,7 +33,7 @@
<aside>
<div class="game_info">
- <span id="year">Year 1</span>
+ <span id="year"></span>
<span id="pool_hero_points"></span>
</div>
<div id="roles">
@@ -62,6 +62,25 @@
<main>
<div id="mapwrap">
<div id="map">
+ <div id="fronts">
+ <div id="northern_front" class="front" style="left: 89px; top: 96px;">
+ <div class="contributions"></div>
+ <span class="value"></span>
+ </div>
+ <div id="aragon_front" class="front" style="left: 340px; top: 182px;">
+ <div class="contributions"></div>
+ <span class="value"></span>
+ </div>
+ <div id="madrid_front" class="front" style="left: 115px; top: 262px;">
+ <div class="contributions"></div>
+ <span class="value"></span>
+ </div>
+ <div id="southern_front" class="front" style="left: 205px; top: 426px;">
+ <div class="contributions"></div>
+ <span class="value"></span>
+ </div>
+ </div>
+ <div id="glory"></div>
<div id="spaces">
</div>
<div id="pieces"></div>
diff --git a/play.js b/play.js
index 3711a13..38d98dd 100644
--- a/play.js
+++ b/play.js
@@ -9,9 +9,32 @@ const TRACK_COUNT = 5;
const TRACK_LENGTH = 11;
const FACTIONS = ['a', 'c', 'm'];
console.log('roles', document.getElementById('roles'));
-let ui = {
+const ui = {
map: document.getElementById('map'),
markers: document.getElementById('markers'),
+ fronts: {
+ a: {
+ front: document.getElementById('aragon_front'),
+ value: document.querySelector('#aragon_front .value'),
+ contributions: document.querySelector('#aragon_front .contributions'),
+ },
+ m: {
+ front: document.getElementById('madrid_front'),
+ value: document.querySelector('#madrid_front .value'),
+ contributions: document.querySelector('#madrid_front .contributions'),
+ },
+ n: {
+ front: document.getElementById('northern_front'),
+ value: document.querySelector('#northern_front .value'),
+ contributions: document.querySelector('#northern_front .contributions'),
+ },
+ s: {
+ front: document.getElementById('southern_front'),
+ value: document.querySelector('#southern_front .value'),
+ contributions: document.querySelector('#southern_front .contributions'),
+ },
+ },
+ glory_container: document.getElementById('glory'),
hand: document.getElementById('hand'),
current_events: document.getElementById('current_events'),
stats: {
@@ -35,10 +58,10 @@ let ui = {
},
tracks: document.getElementById('tracks'),
hero_points: document.querySelector('#role_Anarchist .role_stat'),
+ year: document.getElementById('year'),
blank_markers: [[], [], [], [], []],
bonuses: [],
- fronts: {},
- frontValues: {},
+ tokens_on_front: {},
glory: [],
medaillons: [],
spaces: [],
@@ -142,22 +165,6 @@ const LAYOUT_TRACKS = [
[948, 489],
],
];
-(function build_map() {
- data.fronts.forEach((front, index) => {
- const { id, top, left } = front;
- const element = (ui.fronts[index] = document.createElement('div'));
- element.classList.add('front');
- element.style.left = `${left}px`;
- element.style.top = `${top}px`;
- element.setAttribute('data-front-id', `${id}`);
- ui.map.appendChild(element);
- const frontValueElement = (ui.frontValues[front.id] =
- document.createElement('span'));
- frontValueElement.classList.add('value');
- register_action(element, 'front', id);
- element.appendChild(frontValueElement);
- });
-})();
console.log('ui', ui);
function register_action(e, action, id) {
e.my_action = action;
@@ -205,8 +212,8 @@ function on_init() {
}
for (let g = 0; g < GLORY_COUNT; ++g) {
let e = (ui.glory[g] = document.createElement('div'));
- e.className = 'glory';
- ui.map.appendChild(ui.glory[g]);
+ e.className = 'faction_token';
+ ui.glory_container.appendChild(ui.glory[g]);
e.style.left = LAYOUT_GLORY[g][0] + 'px';
e.style.top = LAYOUT_GLORY[g][1] + 'px';
}
@@ -224,14 +231,24 @@ function on_init() {
register_action(e, 'standee', s);
ui.tracks.appendChild(ui.standees[s]);
}
- console.log('standees', ui.standees);
for (let c = 1; c < CARD_COUNT; ++c) {
let e = (ui.cards[c] = document.createElement('div'));
e.className = 'card';
e.setAttribute('data-card-id', '' + data.cards[c].id);
register_action(e, 'card', c);
}
- console.log('action_register', action_register[0]);
+ data.fronts.forEach((front) => {
+ ui.tokens_on_front[front.id] = {};
+ FACTIONS.forEach((faction_id) => {
+ let e = (ui.tokens_on_front[front.id][faction_id] =
+ document.createElement('div'));
+ e.className = 'faction_token';
+ e.setAttribute('data-faction-id', faction_id);
+ });
+ });
+ Object.keys(ui.fronts).forEach((front_id) => {
+ register_action(ui.fronts[front_id].front, 'front', front_id);
+ });
}
function on_update() {
console.log('on_update', view);
@@ -270,8 +287,13 @@ function on_update() {
ui.standees[i].style.left = LAYOUT_TRACKS[i][view.tracks[i]][0] + 'px';
ui.standees[i].style.top = LAYOUT_TRACKS[i][view.tracks[i]][1] + 'px';
}
- for (let frontId of Object.keys(view.fronts)) {
- ui.frontValues[frontId].replaceChildren(view.fronts[frontId]);
+ for (let front_id of Object.keys(view.fronts)) {
+ const front_data = view.fronts[front_id];
+ ui.fronts[front_id].value.replaceChildren(front_data.value);
+ ui.fronts[front_id].contributions.replaceChildren();
+ for (let faction_id of front_data.contributions) {
+ ui.fronts[front_id].contributions.appendChild(ui.tokens_on_front[front_id][faction_id]);
+ }
}
for (let i = 0; i < view.medaillons.length; ++i) {
if (view.medaillons[i] !== null) {
@@ -291,6 +313,7 @@ function on_update() {
}
for (let e of action_register)
e.classList.toggle('action', is_action(e.my_action, e.my_id));
+ ui.year.replaceChildren(`Year ${view.year}`);
action_button('add_to_front', '+1 to a Front');
action_button('soviet_support', 'Soviet Support');
action_button('collectivization', 'Collectivization');
@@ -322,6 +345,10 @@ function on_update() {
}
function on_log(text) {
let p = document.createElement('div');
+ if (text.match(/^>>/)) {
+ text = text.substring(2);
+ p.className = "ii";
+ }
if (text.match(/^>/)) {
text = text.substring(1);
p.className = 'i';
@@ -333,17 +360,25 @@ function on_log(text) {
text = text.substring(4);
p.className = 'h1';
}
- else if (text.match(/^\.h2/)) {
- text = text.substring(4);
- p.className = 'h2';
+ else if (text.match(/^\.h2\.Moderate/)) {
+ text = text.substring(13);
+ p.className = 'h2 moderate';
}
- else if (text.match(/^\.h3\.allies/)) {
- text = text.substring(10);
- p.className = 'h3 allies';
+ else if (text.match(/^\.h2\.Anarchist/)) {
+ text = text.substring(14);
+ p.className = 'h2 anarchist';
}
- else if (text.match(/^\.h3\.germans/)) {
+ else if (text.match(/^\.h2\.Communist/)) {
+ text = text.substring(14);
+ p.className = 'h2 communist';
+ }
+ else if (text.match(/^\.h2\.fascist/)) {
text = text.substring(11);
- p.className = 'h3 germans';
+ p.className = 'h2 fascist';
+ }
+ else if (text.match(/^\.h2/)) {
+ text = text.substring(4);
+ p.className = 'h2';
}
else if (text.match(/^\.h3/)) {
text = text.substring(4);
diff --git a/play.ts b/play.ts
index 57e8582..e192d6d 100644
--- a/play.ts
+++ b/play.ts
@@ -1,6 +1,6 @@
'use strict';
-import { FactionId, StaticData, View } from './types';
+import { StaticData, View } from './types';
declare function action_button(action: string, text: string): void;
// declare function register_action(element: HTMLElement, type: string, s: number): void;
@@ -23,9 +23,32 @@ const FACTIONS = ['a', 'c', 'm'];
console.log('roles', document.getElementById('roles'));
-let ui = {
+const ui = {
map: document.getElementById('map'),
markers: document.getElementById('markers'),
+ fronts: {
+ a: {
+ front: document.getElementById('aragon_front'),
+ value: document.querySelector('#aragon_front .value'),
+ contributions: document.querySelector('#aragon_front .contributions'),
+ },
+ m: {
+ front: document.getElementById('madrid_front'),
+ value: document.querySelector('#madrid_front .value'),
+ contributions: document.querySelector('#madrid_front .contributions'),
+ },
+ n: {
+ front: document.getElementById('northern_front'),
+ value: document.querySelector('#northern_front .value'),
+ contributions: document.querySelector('#northern_front .contributions'),
+ },
+ s: {
+ front: document.getElementById('southern_front'),
+ value: document.querySelector('#southern_front .value'),
+ contributions: document.querySelector('#southern_front .contributions'),
+ },
+ },
+ glory_container: document.getElementById('glory'),
hand: document.getElementById('hand'),
current_events: document.getElementById('current_events'),
stats: {
@@ -49,10 +72,12 @@ let ui = {
},
tracks: document.getElementById('tracks'),
hero_points: document.querySelector('#role_Anarchist .role_stat'),
+ year: document.getElementById('year'),
blank_markers: [[], [], [], [], []],
bonuses: [],
- fronts: {},
- frontValues: {},
+ // fronts: {},
+ tokens_on_front: {},
+ // front_values: {},
glory: [],
medaillons: [],
spaces: [],
@@ -164,22 +189,26 @@ const LAYOUT_TRACKS = [
];
// @ts-ignore
-(function build_map() {
- data.fronts.forEach((front, index) => {
- const { id, top, left } = front;
- const element = (ui.fronts[index] = document.createElement('div'));
- element.classList.add('front');
- element.style.left = `${left}px`;
- element.style.top = `${top}px`;
- element.setAttribute('data-front-id', `${id}`);
- ui.map.appendChild(element);
- const frontValueElement = (ui.frontValues[front.id] =
- document.createElement('span'));
- frontValueElement.classList.add('value');
- register_action(element, 'front', id);
- element.appendChild(frontValueElement);
- });
-})();
+// (function build_map() {
+// data.fronts.forEach((front) => {
+// const { id, top, left } = front;
+// const element = (ui.fronts[front.id] = document.createElement('div'));
+// element.classList.add('front');
+// element.style.left = `${left}px`;
+// element.style.top = `${top}px`;
+// element.setAttribute('data-front-id', `${id}`);
+// ui.map.appendChild(element);
+// register_action(element, 'front', id);
+
+// // Contribution tokens
+
+// // Value of front
+// const front_value_element = (ui.front_values[front.id] =
+// document.createElement('span'));
+// front_value_element.classList.add('value');
+// element.appendChild(front_value_element);
+// });
+// })();
console.log('ui', ui);
@@ -242,10 +271,11 @@ function on_init() {
ui.map.appendChild(ui.bonuses[b]);
}
+ // Create glory
for (let g = 0; g < GLORY_COUNT; ++g) {
let e = (ui.glory[g] = document.createElement('div'));
- e.className = 'glory';
- ui.map.appendChild(ui.glory[g]);
+ e.className = 'faction_token';
+ ui.glory_container.appendChild(ui.glory[g]);
e.style.left = LAYOUT_GLORY[g][0] + 'px';
e.style.top = LAYOUT_GLORY[g][1] + 'px';
}
@@ -268,8 +298,6 @@ function on_init() {
ui.tracks.appendChild(ui.standees[s]);
}
- console.log('standees', ui.standees);
-
// create card elements
for (let c = 1; c < CARD_COUNT; ++c) {
let e = (ui.cards[c] = document.createElement('div'));
@@ -278,7 +306,20 @@ function on_init() {
register_action(e, 'card', c);
}
- console.log('action_register', action_register[0]);
+ // create tokens to add to fronts
+ data.fronts.forEach((front) => {
+ ui.tokens_on_front[front.id] = {};
+ FACTIONS.forEach((faction_id) => {
+ let e = (ui.tokens_on_front[front.id][faction_id] =
+ document.createElement('div'));
+ e.className = 'faction_token';
+ e.setAttribute('data-faction-id', faction_id);
+ });
+ });
+
+ Object.keys(ui.fronts).forEach((front_id) => {
+ register_action(ui.fronts[front_id].front, 'front', front_id);
+ })
}
// @ts-ignore
@@ -338,8 +379,13 @@ function on_update() {
ui.standees[i].style.top = LAYOUT_TRACKS[i][view.tracks[i]][1] + 'px';
}
- for (let frontId of Object.keys(view.fronts)) {
- ui.frontValues[frontId].replaceChildren(view.fronts[frontId]);
+ for (let front_id of Object.keys(view.fronts)) {
+ const front_data = view.fronts[front_id];
+ ui.fronts[front_id].value.replaceChildren(front_data.value);
+ ui.fronts[front_id].contributions.replaceChildren();
+ for(let faction_id of front_data.contributions) {
+ ui.fronts[front_id].contributions.appendChild(ui.tokens_on_front[front_id][faction_id]);
+ }
}
for (let i = 0; i < view.medaillons.length; ++i) {
@@ -364,6 +410,8 @@ function on_update() {
for (let e of action_register)
e.classList.toggle('action', is_action(e.my_action, e.my_id));
+ ui.year.replaceChildren(`Year ${view.year}`);
+
action_button('add_to_front', '+1 to a Front');
action_button('soviet_support', 'Soviet Support');
action_button('collectivization', 'Collectivization');
@@ -401,6 +449,11 @@ function on_update() {
function on_log(text) {
let p = document.createElement('div');
+ if (text.match(/^>>/)) {
+ text = text.substring(2)
+ p.className = "ii"
+ }
+
if (text.match(/^>/)) {
text = text.substring(1);
p.className = 'i';
@@ -419,15 +472,21 @@ function on_log(text) {
if (text.match(/^\.h1/)) {
text = text.substring(4);
p.className = 'h1';
+ } else if (text.match(/^\.h2\.Moderate/)) {
+ text = text.substring(13);
+ p.className = 'h2 moderate';
+ } else if (text.match(/^\.h2\.Anarchist/)) {
+ text = text.substring(14);
+ p.className = 'h2 anarchist';
+ } else if (text.match(/^\.h2\.Communist/)) {
+ text = text.substring(14);
+ p.className = 'h2 communist';
+ } else if (text.match(/^\.h2\.fascist/)) {
+ text = text.substring(11);
+ p.className = 'h2 fascist';
} else if (text.match(/^\.h2/)) {
text = text.substring(4);
p.className = 'h2';
- } else if (text.match(/^\.h3\.allies/)) {
- text = text.substring(10);
- p.className = 'h3 allies';
- } else if (text.match(/^\.h3\.germans/)) {
- text = text.substring(11);
- p.className = 'h3 germans';
} else if (text.match(/^\.h3/)) {
text = text.substring(4);
p.className = 'h3';
diff --git a/rules.js b/rules.js
index 697ec13..f9cd8e8 100644
--- a/rules.js
+++ b/rules.js
@@ -113,18 +113,27 @@ function setup_bag_of_glory() {
next();
}
function setup_choose_card() {
- console.log('setup_choose_card');
const player_order = get_player_order();
game.engine = player_order.map((faction_id) => create_leaf_node('choose_card', faction_id));
game.engine.push(create_function_node('setup_player_turn'));
- resolve_active_and_proceed();
+ next();
}
function setup_player_turn() {
- console.log('setup_player_turn');
const player_order = get_player_order();
- game.engine = player_order.map((faction_id) => create_seq_node([create_leaf_node('player_turn', faction_id)]));
+ game.engine = player_order.map((faction_id) => create_seq_node([
+ create_function_node('start_of_player_turn', { f: faction_id }),
+ create_leaf_node('player_turn', faction_id),
+ ]));
game.engine.push(create_function_node('resolve_fascist_test'));
game.engine.push(create_function_node('setup_bag_of_glory'));
+ next();
+}
+function start_of_player_turn() {
+ const args = get_active_node_args();
+ console.log('args', args);
+ console.log('args');
+ const player = faction_player_map[args.f];
+ log_h2(player, player);
resolve_active_and_proceed();
}
const engine_functions = {
@@ -134,6 +143,7 @@ const engine_functions = {
setup_bag_of_glory,
setup_choose_card,
setup_player_turn,
+ start_of_player_turn,
resolve_fascist_test,
};
function get_active(engine) {
@@ -156,7 +166,7 @@ function get_active_node(engine = game.engine) {
}
function get_active_node_args() {
const node = get_active_node(game.engine);
- if (node.t === leaf_node) {
+ if (node.t === leaf_node || node.t === function_node) {
return node.a;
}
return null;
@@ -223,11 +233,13 @@ function game_view(state, player) {
glory: game.glory,
hand: game.hands[faction_id],
hero_points: game.hero_points,
+ initiative: game.initiative,
medaillons: game.medaillons,
selected_card: game.chosen_cards[faction_id],
tableaus: game.tableaus,
tracks: game.tracks,
triggered_track_effects: game.triggered_track_effects,
+ year: game.year,
};
if (player !== game.active) {
let inactive = states[game.state].inactive || game.state;
@@ -260,10 +272,22 @@ function setup(seed, _scenario, _options) {
},
engine: [],
fronts: {
- a: -2,
- m: -2,
- n: -2,
- s: -2,
+ a: {
+ value: -2,
+ contributions: [],
+ },
+ m: {
+ value: -2,
+ contributions: [],
+ },
+ n: {
+ value: -2,
+ contributions: [],
+ },
+ s: {
+ value: -2,
+ contributions: [],
+ },
},
glory: [],
hands: {
@@ -313,27 +337,24 @@ function setup(seed, _scenario, _options) {
}
function draw_hand_cards() {
role_ids.forEach((role) => {
- const deck = faction_cards[role];
+ const deck = list_deck(role);
for (let i = 0; i < 5; i++) {
- game.hands[role];
game.hands[role].push(draw_card(deck));
}
});
}
function start_year() {
- console.log('start year');
- log_h1('Year ' + game.year);
game.current_events = [];
draw_hand_cards();
start_turn();
}
function start_turn() {
- log_h2('Turn ' + game.turn);
- const deck = fascist_decks[game.year];
- const cardId = draw_card(deck);
+ log_h1(`Year ${game.year} - Turn ${game.turn}`);
+ const cardId = draw_card(list_deck('fascist'));
game.current_events.push(cardId);
const card = cards[cardId];
- log_h3('Fascist Event: ' + card.title);
+ log_h2('Fascist Event', 'fascist');
+ log(card.title);
game.engine = card.effects.map((effect) => resolve_effect(effect, game.initiative));
game.engine.push({
t: 'f',
@@ -475,10 +496,19 @@ states.choose_area_ap = {
for (const front of fronts) {
gen_action_front(front);
}
+ for (const bonus of bonuses) {
+ if (game.bonuses[bonus] === data_1.OFF) {
+ gen_action_bonus(bonus);
+ }
+ }
+ },
+ bonus(b) {
+ update_bonus(b, data_1.ON);
+ resolve_active_and_proceed();
},
front(f) {
const s = get_active_node_args().strength;
- update_front(f, s);
+ update_front(f, s, get_active_faction_id());
resolve_active_and_proceed();
},
standee(track_id) {
@@ -520,8 +550,7 @@ states.change_bonus = {
},
bonus(b) {
const value = get_active_node_args().v;
- game.bonuses[b] = value;
- log(`${bonus_names[b]} ${value === data_1.ON ? 'on' : 'off'}`);
+ update_bonus(b, value);
resolve_active_and_proceed();
},
skip() {
@@ -712,8 +741,27 @@ function check_activate_icon() {
}
resolve_active_and_proceed();
}
+function check_initiative() {
+ let initiative;
+ if (game.tracks[data_1.LIBERTY] >= 6 && game.tracks[data_1.COLLECTIVIZATION] >= 6) {
+ initiative = data_1.ANARCHISTS_ID;
+ }
+ else if (game.tracks[data_1.GOVERNMENT] <= 5) {
+ initiative = data_1.COMMUNISTS_ID;
+ }
+ else {
+ initiative = data_1.MODERATES_ID;
+ }
+ if (game.initiative === initiative) {
+ return;
+ }
+ game.initiative = initiative;
+ logi(`${faction_player_map[initiative]} claims the Initiative`);
+}
function end_of_turn() {
- log_h2('End of turn');
+ Object.keys(game.fronts).forEach((front_id) => {
+ game.fronts[front_id].contributions = [];
+ });
if (game.turn === 4) {
end_of_year();
}
@@ -734,9 +782,9 @@ function end_of_year() {
}
function resolve_fascist_test() {
console.log('resolve fascist test');
- log_h2('Fascist test is resolved');
+ log_h2('Fascist Test', 'fascist');
const test = get_current_event().test;
- const test_passed = game.fronts[test.front] >= test.value;
+ const test_passed = game.fronts[test.front].value >= test.value;
if (test_passed) {
log('The Test is passed');
}
@@ -768,7 +816,8 @@ function move_track(track_id, change) {
new_value = Math.max(new_value, track_id === data_1.GOVERNMENT ? 1 : 0);
new_value = Math.min(new_value, 10);
game.tracks[track_id] = new_value;
- log(`${get_track_name(track_id)} to ${new_value}`);
+ logi(`${get_track_name(track_id)} to ${new_value}`);
+ check_initiative();
const triggered_spaces = change > 0
? make_list(current_value + 1, new_value).reverse()
: make_list(new_value, current_value - 1);
@@ -786,9 +835,28 @@ function move_track(track_id, change) {
}
});
}
-function update_front(f, change) {
- game.fronts[f] += change;
- log(`${front_names[f]}: ${change > 0 ? '+' : ''}${change}`);
+function update_bonus(bonus_id, status) {
+ if (game.bonuses[bonus_id] === status) {
+ return;
+ }
+ game.bonuses[bonus_id] = status;
+ logi(`${bonus_names[bonus_id]} ${status === data_1.ON ? 'on' : 'off'}`);
+}
+function update_front(f, change, faction_id = null) {
+ const player_token_on_front = faction_id !== null && game.fronts[f].contributions.includes(faction_id);
+ if (game.bonuses[data_1.TEAMWORK_BONUS] === data_1.ON &&
+ change > 0 &&
+ faction_id !== null &&
+ !player_token_on_front &&
+ game.fronts[f].contributions.length > 0) {
+ change += 1;
+ }
+ game.fronts[f].value += change;
+ logi(`${front_names[f]}: ${change > 0 ? '+' : ''}${change}`);
+ if (faction_id !== null &&
+ !game.fronts[f].contributions.includes(faction_id)) {
+ game.fronts[f].contributions.push(faction_id);
+ }
}
function create_effects_node(effects) {
const nodes = effects.reduce((accrued, current) => {
@@ -855,9 +923,9 @@ function lose_hero_point(faction, value) {
}
}
function get_fronts_closest_to(target) {
- const values = Object.values(game.fronts);
+ const values = Object.values(game.fronts).map((front) => front.value);
const targetValue = target === 'd' ? Math.min(...values) : Math.max(...values);
- return Object.keys(game.fronts).filter((frontId) => game.fronts[frontId] === targetValue);
+ return Object.keys(game.fronts).filter((frontId) => game.fronts[frontId].value === targetValue);
}
function log_br() {
if (game.log.length > 0 && game.log[game.log.length - 1] !== '')
@@ -866,16 +934,20 @@ function log_br() {
function log(msg) {
game.log.push(msg);
}
+function logi(msg) {
+ log('>' + msg);
+}
function log_h1(msg) {
log_br();
log('.h1 ' + msg);
log_br();
}
-function log_h2(msg) {
+function log_h2(msg, player) {
log_br();
- log('.h2 ' + msg);
+ log(`.h2${player ? `.${player}` : ''} ${msg}`);
log_br();
}
+log;
function log_h3(msg) {
log_br();
log('.h3 ' + msg);
@@ -983,6 +1055,20 @@ function set_delete(set, item) {
}
}
}
+function list_deck(id) {
+ const deck = [];
+ const card_list = id === 'fascist' ? fascist_decks[game.year] : faction_cards[id];
+ card_list.forEach((card) => {
+ if (id === 'fascist' && (game.discard.f.includes(card))) {
+ return;
+ }
+ else if (id !== 'fascist' && (game.hands[id].includes(card) || game.discard[id].includes(card))) {
+ return;
+ }
+ deck.push(card);
+ });
+ return deck;
+}
function array_remove(array, index) {
let n = array.length;
for (let i = index + 1; i < n; ++i)
diff --git a/rules.ts b/rules.ts
index ee9b269..c6f01ab 100644
--- a/rules.ts
+++ b/rules.ts
@@ -214,23 +214,33 @@ function setup_bag_of_glory() {
}
function setup_choose_card() {
- console.log('setup_choose_card');
const player_order = get_player_order();
game.engine = player_order.map((faction_id) =>
create_leaf_node('choose_card', faction_id)
);
game.engine.push(create_function_node('setup_player_turn'));
- resolve_active_and_proceed();
+ next();
}
function setup_player_turn() {
- console.log('setup_player_turn');
const player_order = get_player_order();
game.engine = player_order.map((faction_id) =>
- create_seq_node([create_leaf_node('player_turn', faction_id)])
+ create_seq_node([
+ create_function_node('start_of_player_turn', { f: faction_id }),
+ create_leaf_node('player_turn', faction_id),
+ ])
);
game.engine.push(create_function_node('resolve_fascist_test'));
game.engine.push(create_function_node('setup_bag_of_glory'));
+ next();
+}
+
+function start_of_player_turn() {
+ const args = get_active_node_args();
+ console.log('args', args);
+ console.log('args');
+ const player = faction_player_map[args.f];
+ log_h2(player, player);
resolve_active_and_proceed();
}
@@ -241,6 +251,7 @@ const engine_functions: Record<string, Function> = {
setup_bag_of_glory,
setup_choose_card,
setup_player_turn,
+ start_of_player_turn,
resolve_fascist_test,
};
@@ -300,7 +311,7 @@ function get_active_node(
function get_active_node_args(): any {
const node = get_active_node(game.engine);
- if (node.t === leaf_node) {
+ if (node.t === leaf_node || node.t === function_node) {
return node.a;
}
return null;
@@ -390,11 +401,13 @@ function game_view(state: Game, player: Player) {
glory: game.glory,
hand: game.hands[faction_id],
hero_points: game.hero_points,
+ initiative: game.initiative,
medaillons: game.medaillons,
selected_card: game.chosen_cards[faction_id],
tableaus: game.tableaus,
tracks: game.tracks,
triggered_track_effects: game.triggered_track_effects,
+ year: game.year,
};
if (player !== game.active) {
@@ -432,10 +445,22 @@ export function setup(seed: number, _scenario: string, _options: unknown) {
},
engine: [],
fronts: {
- a: -2,
- m: -2,
- n: -2,
- s: -2,
+ a: {
+ value: -2,
+ contributions: [],
+ },
+ m: {
+ value: -2,
+ contributions: [],
+ },
+ n: {
+ value: -2,
+ contributions: [],
+ },
+ s: {
+ value: -2,
+ contributions: [],
+ },
},
glory: [],
hands: {
@@ -487,9 +512,8 @@ export function setup(seed: number, _scenario: string, _options: unknown) {
function draw_hand_cards() {
role_ids.forEach((role) => {
- const deck = faction_cards[role];
+ const deck = list_deck(role);
for (let i = 0; i < 5; i++) {
- game.hands[role];
game.hands[role].push(draw_card(deck));
}
});
@@ -498,22 +522,21 @@ function draw_hand_cards() {
// #endregion
function start_year() {
- console.log('start year')
- log_h1('Year ' + game.year);
+ // log_h1('Year ' + game.year);
game.current_events = [];
draw_hand_cards();
start_turn();
}
function start_turn() {
- log_h2('Turn ' + game.turn);
+ log_h1(`Year ${game.year} - Turn ${game.turn}`);
- const deck = fascist_decks[game.year];
- const cardId = draw_card(deck);
+ const cardId = draw_card(list_deck('fascist'));
game.current_events.push(cardId);
const card = cards[cardId] as EventCard;
- log_h3('Fascist Event: ' + card.title);
+ log_h2('Fascist Event', 'fascist');
+ log(card.title);
game.engine = card.effects.map((effect) =>
resolve_effect(effect, game.initiative)
@@ -676,10 +699,20 @@ states.choose_area_ap = {
for (const front of fronts) {
gen_action_front(front);
}
+ for (const bonus of bonuses) {
+ if (game.bonuses[bonus] === OFF) {
+ gen_action_bonus(bonus);
+ }
+ }
+ },
+ bonus(b: number) {
+ update_bonus(b, ON);
+ // TODO: insert action in case other bonus is OFF and AP left
+ resolve_active_and_proceed();
},
front(f: string) {
- const s = get_active_node_args().strength;
- update_front(f, s);
+ const s: number = get_active_node_args().strength;
+ update_front(f, s, get_active_faction_id());
resolve_active_and_proceed();
},
standee(track_id: number) {
@@ -723,8 +756,7 @@ states.change_bonus = {
},
bonus(b: number) {
const value = get_active_node_args().v;
- game.bonuses[b] = value;
- log(`${bonus_names[b]} ${value === ON ? 'on' : 'off'}`);
+ update_bonus(b, value);
resolve_active_and_proceed();
},
skip() {
@@ -1009,9 +1041,28 @@ function check_activate_icon() {
resolve_active_and_proceed();
}
+function check_initiative() {
+ let initiative: FactionId;
+ if (game.tracks[LIBERTY] >= 6 && game.tracks[COLLECTIVIZATION] >= 6) {
+ initiative = ANARCHISTS_ID;
+ } else if (game.tracks[GOVERNMENT] <= 5) {
+ initiative = COMMUNISTS_ID;
+ } else {
+ initiative = MODERATES_ID;
+ }
+
+ if (game.initiative === initiative) {
+ return;
+ }
+ game.initiative = initiative;
+ logi(`${faction_player_map[initiative]} claims the Initiative`);
+}
+
function end_of_turn() {
- // REMOVE player tokens from the Fronts;
- log_h2('End of turn');
+ Object.keys(game.fronts).forEach((front_id) => {
+ game.fronts[front_id].contributions = [];
+ });
+ // log_h2('End of turn');
if (game.turn === 4) {
end_of_year();
} else {
@@ -1034,10 +1085,10 @@ function end_of_year() {
function resolve_fascist_test() {
console.log('resolve fascist test');
- log_h2('Fascist test is resolved');
+ log_h2('Fascist Test', 'fascist');
const test = get_current_event().test;
- const test_passed = game.fronts[test.front] >= test.value;
+ const test_passed = game.fronts[test.front].value >= test.value;
if (test_passed) {
log('The Test is passed');
} else {
@@ -1075,7 +1126,10 @@ function move_track(track_id: number, change: number) {
new_value = Math.max(new_value, track_id === GOVERNMENT ? 1 : 0);
new_value = Math.min(new_value, 10);
game.tracks[track_id] = new_value;
- log(`${get_track_name(track_id)} to ${new_value}`);
+ logi(`${get_track_name(track_id)} to ${new_value}`);
+
+ check_initiative();
+
const triggered_spaces =
change > 0
? make_list(current_value + 1, new_value).reverse()
@@ -1098,10 +1152,39 @@ function move_track(track_id: number, change: number) {
});
}
+function update_bonus(bonus_id: number, status: number) {
+ if (game.bonuses[bonus_id] === status) {
+ return;
+ }
+ game.bonuses[bonus_id] = status;
+ logi(`${bonus_names[bonus_id]} ${status === ON ? 'on' : 'off'}`);
+}
+
// TODO: acccount for victory / defeat of front
-function update_front(f: string, change: number) {
- game.fronts[f] += change;
- log(`${front_names[f]}: ${change > 0 ? '+' : ''}${change}`);
+function update_front(
+ f: string,
+ change: number,
+ faction_id: FactionId | null = null
+) {
+ const player_token_on_front =
+ faction_id !== null && game.fronts[f].contributions.includes(faction_id);
+ if (
+ game.bonuses[TEAMWORK_BONUS] === ON &&
+ change > 0 &&
+ faction_id !== null &&
+ !player_token_on_front &&
+ game.fronts[f].contributions.length > 0
+ ) {
+ change += 1;
+ }
+ game.fronts[f].value += change;
+ logi(`${front_names[f]}: ${change > 0 ? '+' : ''}${change}`);
+ if (
+ faction_id !== null &&
+ !game.fronts[f].contributions.includes(faction_id)
+ ) {
+ game.fronts[f].contributions.push(faction_id);
+ }
}
function create_effects_node(effects: Effect[]): EngineNode {
@@ -1276,11 +1359,11 @@ function lose_hero_point(faction: FactionId, value: number) {
// #region FRONTS
function get_fronts_closest_to(target: 'd' | 'v') {
- const values = Object.values(game.fronts);
+ const values = Object.values(game.fronts).map((front) => front.value);
const targetValue =
target === 'd' ? Math.min(...values) : Math.max(...values);
return Object.keys(game.fronts).filter(
- (frontId) => game.fronts[frontId] === targetValue
+ (frontId) => game.fronts[frontId].value === targetValue
);
}
@@ -1305,12 +1388,12 @@ function log(msg: string) {
// game.log.push(`C${cap}.`)
// }
-// function logi(msg: string) {
-// game.log.push('>' + msg);
-// }
+function logi(msg: string) {
+ log('>' + msg);
+}
// function logii(msg: string) {
-// game.log.push('>>' + msg);
+// log('>>' + msg);
// }
function log_h1(msg: string) {
@@ -1319,12 +1402,14 @@ function log_h1(msg: string) {
log_br();
}
-function log_h2(msg: string) {
+function log_h2(msg: string, player?: Player | 'fascist') {
log_br();
- log('.h2 ' + msg);
+ log(`.h2${player ? `.${player}` : ''} ${msg}`);
log_br();
}
+log;
+
// function log_h2_active(msg: string) {
// log_br();
// log('.h2 ' + msg);
@@ -1473,6 +1558,20 @@ function set_delete<T>(set: T[], item: T) {
}
}
+function list_deck(id: FactionId | 'fascist') {
+ const deck = [];
+ const card_list = id === 'fascist' ? fascist_decks[game.year] : faction_cards[id];
+ card_list.forEach((card) => {
+ if (id === 'fascist' && (game.discard.f.includes(card))) {
+ return
+ } else if (id !== 'fascist' && (game.hands[id].includes(card) || game.discard[id].includes(card))) {
+ return;
+ }
+ deck.push(card)
+ })
+ return deck;
+}
+
// #endregion
// #region ARRAY
diff --git a/types.d.ts b/types.d.ts
index 59d9d9d..da8fe25 100644
--- a/types.d.ts
+++ b/types.d.ts
@@ -27,10 +27,22 @@ export interface Game {
discard: Record<FactionId | 'f', number[]>;
engine: EngineNode[];
fronts: {
- a: number;
- m: number;
- n: number;
- s: number;
+ a: {
+ value: number;
+ contributions: FactionId[];
+ };
+ m: {
+ value: number;
+ contributions: FactionId[];
+ };
+ n: {
+ value: number;
+ contributions: FactionId[];
+ };
+ s: {
+ value: number;
+ contributions: FactionId[];
+ };
};
glory: FactionId[];
hands: Record<FactionId, CardId[]>;
@@ -71,10 +83,12 @@ export interface View {
glory: Game['glory'];
hand: CardId[];
hero_points: Game['hero_points'];
+ initiative: Game['initiative'];
medaillons: Game['medaillons'];
tableaus: Game['tableaus'];
tracks: number[];
triggered_track_effects: Game['triggered_track_effects'];
+ year: number;
}
export type States = {