-
Notifications
You must be signed in to change notification settings - Fork 0
/
Game.pde
264 lines (222 loc) · 8.41 KB
/
Game.pde
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
import java.util.*;
import java.util.concurrent.*;
//NAMING and LOBBY are exclusive to the client-side aspect of the game
//LOBBY indicates waiting for more players to join the game
enum GameState {
HOSTING, ROLES, PLAYING, RESULTS;
}
enum PlayState {
NEWS, NOMINATION, INVEST, VOTING, LYNCHING, NIGHT
}
class Game {
static final float ROLE_RATIO = 0.5; //Only for debugging
// static final float ROLE_RATIO = 0.4;
int timer;
int pingTimer;
boolean angelsWin = false;
GameState myState = GameState.HOSTING;
PlayState myPlayState = PlayState.NIGHT;
Host hostGame = new Host();
Day myDay = new Day();
HashMap<String, Player> allPlayers = new HashMap<String, Player>();
ArrayList<String> playerNames = new ArrayList<String>();
Game() {
pingTimer = millis();
}
void update() {
fill(Button.DEFAULT_TEXT_FILL);
textSize(TEXT_SIZE);
ping();
}
void ping() {
//TODO
//Only ping players when setting up the game
//Once it's set up, no more players can join
//Ensuring the server is pinged approximately once a second
if (millis() - pingTimer > 1000) {
pingPlayers();
hostGame.ping();
pingTimer = millis();
}
}
void draw() {
//TODO
//Add a textual description for each of the game states
//So if it's night time, the screen will tell everyone to
//be quiet and look at their phone until it says it's day time
//Angel's perform their murder at this time
//Hope people don't cheat
update();
drawPlayers();
switch(myState) {
case HOSTING:
if (playerNames.isEmpty()) {
textSize(TITLE_TEXT_SIZE);
drawText(String.format("The game room is set up at \"%s\"\n\nJoin the game "
+ "by entering that URL onto your phone. When everyone's ready, press the "
+ "button.", hostGame.getGameURL()));
textSize(TEXT_SIZE);
}
else {
rectMode(CENTER);
text(String.format("Room URL:\n%s", hostGame.getGameURL()), width * 0.75, height * 0.15,
width * 0.5, height * 0.25);
rectMode(CORNER);
}
hostGame.draw();
break;
case ROLES:
//Allow players to see their roles
//Stay here for x seconds. Long enough for everyone to see their roles.
//Then switch the game state once everyone is familiar with their roles
drawText("Your roles have been assigned, you can find them on your device.");
//Waiting for 5 seconds to pass before updating the states
if (millis() - timer > 5000) {
updateStates(GameState.PLAYING, PlayState.NEWS);
myDay.startTimer();
}
break;
case PLAYING:
myDay.draw();
break;
case RESULTS:
if (angelsWin) drawText("The Angels won the game and killed the last human!");
else drawText("The Humans won the game!");
break;
}
}
/*
Draws the specified text in the center of the screen.
*/
void drawText(String displayText) {
rectMode(CENTER);
fill(Button.DEFAULT_TEXT_FILL);
text(displayText, width / 2, height / 2, width * 0.75, height * 0.5);
rectMode(CORNER);
}
/*
Writes the names of all the players who have joined the lobby
*/
void drawPlayers() {
if (myState == GameState.HOSTING) {
for (int i = 0; i < playerNames.size(); i++) {
int yMod = TEXT_SIZE * 2 * i;
text(playerNames.get(i) + " joined the lobby.", width / 5, height * 0.1 + yMod);
}
}
}
void mouseClick() {
if (myState == GameState.HOSTING) hostGame.mouseClick();
}
/**
* Updates both the Game and Play state stored on the server
*/
void updateStates(GameState newGameState, PlayState newPlayState) {
myState = (newGameState != null) ? newGameState : myState;
myPlayState = (newPlayState != null) ? newPlayState : myPlayState;
JSONObject reqBody = new JSONObject();
reqBody.setString("state", myState.name());
reqBody.setString("playState", myPlayState.name());
hostGame.postData("admin/state", reqBody);
}
/*
Updates the current state of game.
*/
void updateGameState(GameState newState) {
updateStates(newState, null);
}
/*
Update the current state of play.
Only utilised while the GameState is PLAYING.
*/
void updatePlayState(PlayState newState) {
updateStates(null, newState);
}
/*
Closes the lobby from any further join requests from players.
Subsequently allocates roles to each of the connected players.
*/
void startGame() {
hostGame.sendRequest("admin/start");
allocateRoles();
updateAllPlayers(allPlayers);
updateGameState(GameState.ROLES);
timer = millis();
}
/*
Assigns roles to all of the connected players.
*/
void allocateRoles() {
JSONArray players = new JSONArray();
JSONObject postData = new JSONObject();
int numAngels = (int) (allPlayers.size() * ROLE_RATIO);
ArrayList<Player> roleless = new ArrayList<Player>();
roleless.addAll(allPlayers.values());
//Assigning all the angels
for (int i = 0; i < numAngels; i++) {
int randomPlayer = (int) random(roleless.size());
roleless.get(randomPlayer).setRole(Roles.ANGEL);
roleless.remove(randomPlayer);
}
//Leaving each available player as a human
for (Player mortal : roleless) mortal.setRole(Roles.HUMAN);
//Formatting the Player objects into an equivalent JSON array of players
//which is to be sent to the server
int i = 0;
for (Player player : allPlayers.values()) players.setJSONObject(i++, player.toJSON());
postData.setJSONArray("player_data", players);
hostGame.postData("admin/players", postData);
}
/*
Pings the server to retrieve all the currently connected players.
*/
void pingPlayers() {
ArrayList<String> newPlayers = new ArrayList<String>();
newPlayers = hostGame.sendRequest("players");
Iterator<String> playerIter = playerNames.iterator();
while(playerIter.hasNext()) {
String removedPlayer = playerIter.next();
if (!newPlayers.contains(removedPlayer)) {
allPlayers.remove(removedPlayer);
playerIter.remove();
}
}
newPlayers.removeAll(playerNames);
for (String player : newPlayers) allPlayers.put(player, new Player(player));
playerNames.addAll(newPlayers);
}
/*
"Proxy" to send a GET request to the server
Just eliminating the need to have a getter for hostGame and later
perform the request from there
*/
ArrayList<String> sendRequest(String endpoint) {
return hostGame.sendRequest(endpoint);
}
/*
Same idea as the sendRequest function, except for POST requests.
*/
ArrayList<String> postData(String endpoint, JSONObject data) {
return hostGame.postData(endpoint, data);
}
PlayState getPlayState() {
return myPlayState;
}
Day getDay() {
return myDay;
}
HashMap<String, Player> getPlayerMap() {
return allPlayers;
}
void killPlayer(String playerName) {
allPlayers.get(playerName).kill();
updateAllPlayers(allPlayers);
}
void setAngelWin(boolean haveAngelsWon) {
angelsWin = haveAngelsWon;
}
void updateAllPlayers(HashMap<String, Player> newPlayers) {
allPlayers = newPlayers;
hostGame.postData("admin/players/states", new Player().listify(newPlayers));
}
}