summaryrefslogtreecommitdiff
path: root/rules.js
blob: 142e0c44b0d812d52b8f93e4cb1e91f5439a66fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
"use strict";

let game = null;
let view = null;

exports.roles = [ "Axis", "Allied" ];

exports.scenarios = [
	"1940",
	"1941",
	"1941-42",
	"Crusader",
	"Battleaxe",
	"1942",
	"Gazala",
	"Pursuit to Alamein",
];

exports.ready = function (scenario, options, players) {
	return players.length === 2;
}

function random(n) {
	return ((game.seed = game.seed * 69621 % 0x7fffffff) / 0x7fffffff) * n | 0;
}

function shuffle(deck) {
	for (let i = deck.length - 1; i > 0; --i) {
		let j = random(i + 1);
		let tmp = deck[j];
		deck[j] = deck[i];
		deck[i] = tmp;
	}
}

function remove_from_array(array, item) {
	let i = array.indexOf(item);
	if (i >= 0)
		array.splice(i, 1);
}

function logbr() {
	if (game.log.length > 0 && game.log[game.log.length-1] !== "")
		game.log.push("");
}

function log(msg) {
	game.log.push(msg);
}

function clear_undo() {
	game.undo = [];
}

function push_undo() {
	game.undo.push(JSON.stringify(game, (k,v) => {
		if (k === 'undo') return 0;
		if (k === 'log') return v.length;
		return v;
	}));
}

function pop_undo() {
	let save_undo = game.undo;
	let save_log = game.log;
	game = JSON.parse(save_undo.pop());
	game.undo = save_undo;
	save_log.length = game.log;
	game.log = save_log;
}

function gen_action(action, argument) {
	if (argument !== undefined) {
		if (!(action in view.actions)) {
			view.actions[action] = [ argument ];
		} else {
			if (!view.actions[action].includes(argument))
				view.actions[action].push(argument);
		}
	} else {
		view.actions[action] = 1;
	}
}

let states = {};

exports.setup = function (seed, scenario, options) {
	game = {
		seed: seed,
		log: [],
		undo: [],
	};
	return game;
}

exports.action = function (state, current, action, arg) {
	game = state;
	update_aliases();
	let S = states[game.state];
	if (action in S) {
		S[action](arg, current);
	} else {
		if (action === 'undo' && game.undo && game.undo.length > 0)
			pop_undo();
		else
			throw new Error("Invalid action: " + action);
	}
	return game;
}

exports.resign = function (state, current) {
	// No resigning allowed.
	return state;
}

exports.view = function(state, current) {
	game = state;
	update_aliases();

	view = {
		log: game.log,
		active: game.active,
		prompt: null,
	};

	if (current === 'Observer' || game.active !== current) {
		view.prompt = `Waiting for ${game.active} \u2014 ${game.state}...`;
	} else {
		view.actions = {}
		states[game.state].prompt();
		if (game.undo && game.undo.length > 0)
			view.actions.undo = 1;
		else
			view.actions.undo = 0;
	}

	return view;
}