updated infection

This commit is contained in:
Peli de Halleux 2017-05-31 13:22:08 -07:00
parent d6ead4fad4
commit da9b180e17

View File

@ -20,20 +20,33 @@ If any player survives the outbreak, the game is won. Otherwise try again!
### How to play ### How to play
Press A+B to enter master mode (1 per game). Press `A+B` to enter master mode (1 per game).
Wait for players to be paired. The number of paired player will display on screen. Wait for players to be paired. The number of paired player will display on screen.
An icon will appear on player's screen. A letter will appear on the player's screen, this letter is the player's identity.
Press A+B to start the infection game. The master will pick a random player as patient zero. Once all your players are registered, press `A+B` to start the infection game.
The game will pick a random player as **patient zero**.
A player will transmit the disease if close enough (RSSI) and with a certain probability (TRANSMISSIONPROB). A player will transmit the disease if close enough (`RSSI`) and with a certain probability (`TRANSMISSIONPROB`).
During the incudation phase (INCUBATION), the player does not show any sign of illness (happy face). During the incudation phase (`INCUBATION`), the player does not show any sign of illness (happy face).
After that phase, the sad face shows up. After that phase, the player gets sick and shows a sad face on the screen. After the sick face, the player dies and a skull shows up.
Player control: Once the game is over, the @boardname@ will show the player id (A,B,C...), health and
* ``A`` button: show identity icon who infected him. The master @boardname@ will show the identity of patient zero.
* ``B`` button: show current infection status
Icons used in the game:
* Pairing: IconNames.Ghost
* Paired: IconNames.Happy
* Dead: IconNames.Skull
* Sick: IconNames.Sad
* Incubating: IconNames.Confused
* Healthy: IconNames.Happy
https://pxt.microbit.org/_gymCJCWPbiDu
### JavaScript code
```typescript ```typescript
/** /**
@ -54,19 +67,26 @@ Player control:
* During the incudation phase (INCUBATION), the player does not show any sign * During the incudation phase (INCUBATION), the player does not show any sign
* of illness. After that phase, the sad face shows up. * of illness. After that phase, the sad face shows up.
* *
* Player control: * The game will automatically stop once all players are dead or healthy. The master can
* A button: show identity icon * also press A+B again to stop the game.
* B button: show current infection status *
* Master control: * Once the game is over, the micro:bit will show the player id (A,B,C...), health and
* A button: show patient zero identity + number of players * who infected him.
* Sad face = infected *
* Happy face = not infected * Icons used in the game:
*
* Pairing: IconNames.Ghost
* Paired: IconNames.Happy
* Dead: IconNames.Skull
* Sick: IconNames.Sad
* Incubating: IconNames.Confused
* Healthy: IconNames.Happy
*
*/ */
const INCUBATION = 20000; // time before showing symptoms const INCUBATION = 20000; // time before showing symptoms
const DEATH = 40000; // time before dying off the disease const DEATH = 40000; // time before dying off the disease
const RSSI = -48; // db const RSSI = -45; // db
const TRANSMISSIONPROB = 80; // % const TRANSMISSIONPROB = 40; // % probability to transfer disease
enum GameState { enum GameState {
Stopped, Stopped,
@ -82,23 +102,40 @@ enum HealthState {
Dead Dead
} }
const GameIcons = {
Pairing: IconNames.Ghost,
Paired: IconNames.Happy,
Dead: IconNames.Skull,
Sick: IconNames.Sad,
Incubating: IconNames.Confused,
Healthy: IconNames.Happy
}
const playerIcons = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
class Player { class Player {
id: number; id: number;
icon: number; icon: number;
health: HealthState; health: HealthState;
show() {
basic.showString(playerIcons[this.icon]);
}
} }
// common state
let state = GameState.Stopped; let state = GameState.Stopped;
// master state
let master = false; let master = false;
let patientZero: Player; let patientZero: Player;
const players: Player[] = [];
// player state
let paired = false; let paired = false;
let infectedBy = 0; // who infected (icon id) let infectedBy = -1; // who infected (playerIcon)
let infectedTime = 0; // local time when infection happened let infectedTime = 0; // local time when infection happened
let icon = 0; // player icon and identity let playerIcon = -1; // player icon and identity
let health = HealthState.Healthy; let health = HealthState.Healthy;
const players: Player[] = [];
// get a player instance (creates one as needed) // get a player instance (creates one as needed)
function player(id: number): Player { function player(id: number): Player {
for (const p of players) for (const p of players)
@ -107,12 +144,8 @@ function player(id: number): Player {
// add player to game // add player to game
let p = new Player(); let p = new Player();
p.id = id; p.id = id;
p.icon = players.length ? players[players.length - 1].icon + 1 : 2; p.icon = (players.length + 1) % playerIcons.length;
p.health = HealthState.Healthy; p.health = HealthState.Healthy;
// don't use sad, happy
if (p.icon == IconNames.Happy) p.icon += 2;
if (p.icon == IconNames.Asleep) p.icon++;
if (p.icon == IconNames.Skull) p.icon++;
players.push(p); players.push(p);
serial.writeLine(`player ==> ${p.id}`) serial.writeLine(`player ==> ${p.id}`)
@ -127,43 +160,65 @@ function allDead(): boolean {
function gameOver() { function gameOver() {
state = GameState.Over; state = GameState.Over;
basic.showIcon(patientZero.icon); if (patientZero)
patientZero.show();
} }
function gameFace() { function gameFace() {
switch (state) { switch (state) {
case GameState.Stopped: case GameState.Stopped:
basic.showIcon(GameIcons.Pairing);
break;
case GameState.Pairing: case GameState.Pairing:
basic.showIcon(paired ? IconNames.Happy : IconNames.Ghost); if (playerIcon > -1)
basic.showString(playerIcons[playerIcon]);
else
basic.showIcon(paired ? GameIcons.Paired : GameIcons.Pairing, 1);
break; break;
case GameState.Running: case GameState.Running:
switch (health) { switch (health) {
case HealthState.Dead: case HealthState.Dead:
basic.showIcon(IconNames.Skull); basic.showIcon(GameIcons.Dead, 1);
break; break;
case HealthState.Sick: case HealthState.Sick:
basic.showIcon(IconNames.Sad); basic.showIcon(GameIcons.Sick, 1);
break; break;
default: default:
basic.showIcon(IconNames.Happy); basic.showIcon(GameIcons.Healthy, 1);
break; break;
} }
break; break;
case GameState.Over: case GameState.Over:
// show id
basic.showString(playerIcons[playerIcon]);
basic.pause(2000);
// show health
switch (health) { switch (health) {
case HealthState.Dead: case HealthState.Dead:
basic.showIcon(IconNames.Skull); basic.showIcon(GameIcons.Dead, 2000);
break; break;
case HealthState.Sick: case HealthState.Sick:
basic.showIcon(IconNames.Sad); basic.showIcon(GameIcons.Sick, 2000);
break; break;
case HealthState.Incubating: case HealthState.Incubating:
basic.showIcon(IconNames.Asleep); basic.showIcon(GameIcons.Incubating, 2000);
break; break;
default: default:
basic.showIcon(IconNames.Happy); basic.showIcon(GameIcons.Healthy, 2000);
break; break;
} }
// show how infected
if (infectedBy > -1) {
basic.showString(" INFECTED BY");
basic.showString(playerIcons[infectedBy]);
basic.pause(2000);
} else {
basic.showString(" PATIENT ZERO");
basic.pause(2000);
}
// show score
game.showScore();
basic.pause(1000);
break; break;
} }
} }
@ -177,10 +232,14 @@ input.onButtonPressed(Button.AB, () => {
state = GameState.Pairing; state = GameState.Pairing;
serial.writeLine("registered as master"); serial.writeLine("registered as master");
radio.setTransmitPower(7); // beef up master signal radio.setTransmitPower(7); // beef up master signal
basic.showString("M"); basic.showString("0");
return;
} }
if (!master) return; // master only beyond this
// launch game // launch game
else if (state == GameState.Pairing && master) { if (state == GameState.Pairing) {
// pick 1 player and infect him // pick 1 player and infect him
patientZero = players[Math.random(players.length)]; patientZero = players[Math.random(players.length)];
while (patientZero.health == HealthState.Healthy) { while (patientZero.health == HealthState.Healthy) {
@ -193,45 +252,13 @@ input.onButtonPressed(Button.AB, () => {
serial.writeLine(`game started ${players.length} players`); serial.writeLine(`game started ${players.length} players`);
// show startup // show startup
basic.showString("R"); basic.showIcon(GameIcons.Dead);
} // end game } // end game
else if (state == GameState.Running && master) { else if (state == GameState.Running) {
gameOver(); gameOver();
} }
}) })
// display your icon
input.onButtonPressed(Button.A, () => {
led.stopAnimation()
if (master) {
if (patientZero)
basic.showIcon(patientZero.icon);
basic.showNumber(players.length);
}
else {
basic.showIcon(icon);
gameFace();
game.showScore();
}
})
// display who infected you
input.onButtonPressed(Button.B, () => {
if (master) {
let c = 0;
for (const p of players)
if (p.health == HealthState.Dead) c++;
basic.showNumber(c);
} else {
led.stopAnimation()
if (infectedBy)
basic.showIcon(infectedBy);
else
basic.showIcon(IconNames.Happy)
gameFace();
}
})
radio.setGroup(42); radio.setGroup(42);
radio.setTransmitSerialNumber(true) radio.setTransmitSerialNumber(true)
radio.onDataPacketReceived(({ time, receivedNumber, receivedString, signal, serial: id }) => { radio.onDataPacketReceived(({ time, receivedNumber, receivedString, signal, serial: id }) => {
@ -256,20 +283,12 @@ radio.onDataPacketReceived(({ time, receivedNumber, receivedString, signal, seri
} else { } else {
if (receivedString == "state") { if (receivedString == "state") {
// update game state // update game state
let oldState = state;
state = receivedNumber as GameState; state = receivedNumber as GameState;
if (oldState != state) { } else if (infectedBy < 0 &&
switch (state) {
case GameState.Pairing:
basic.showString("P");
break;
}
}
} else if (!infectedBy &&
receivedString == "infect" receivedString == "infect"
&& receivedNumber == control.deviceSerialNumber()) { && receivedNumber == control.deviceSerialNumber()) {
// infected by master // infected by master
infectedBy = 1; // infected my master infectedBy = 0; // infected my master
infectedTime = input.runningTime(); infectedTime = input.runningTime();
health = HealthState.Incubating; health = HealthState.Incubating;
serial.writeLine(`infected ${control.deviceSerialNumber()}`); serial.writeLine(`infected ${control.deviceSerialNumber()}`);
@ -287,12 +306,10 @@ radio.onDataPacketReceived(({ time, receivedNumber, receivedString, signal, seri
// paired! // paired!
serial.writeLine(`player paired ==> ${control.deviceSerialNumber()}`) serial.writeLine(`player paired ==> ${control.deviceSerialNumber()}`)
paired = true; paired = true;
basic.showString("R");
return; return;
} }
else if (paired && receivedString == "i" + control.deviceSerialNumber().toString()) { else if (paired && receivedString == "i" + control.deviceSerialNumber().toString()) {
icon = receivedNumber; playerIcon = receivedNumber;
basic.showIcon(icon);
} }
break; break;
case GameState.Running: case GameState.Running:
@ -305,7 +322,8 @@ radio.onDataPacketReceived(({ time, receivedNumber, receivedString, signal, seri
infectedTime = input.runningTime(); infectedTime = input.runningTime();
health = HealthState.Incubating; health = HealthState.Incubating;
} }
} else if (receivedString == "health" && signal > RSSI) { } else if (health != HealthState.Dead
&& receivedString == "health" && signal > RSSI) {
game.addScore(1); game.addScore(1);
} }
break; break;
@ -331,15 +349,19 @@ basic.forever(() => {
radio.sendValue("h" + p.id, p.health); radio.sendValue("h" + p.id, p.health);
} }
break; break;
case GameState.Over:
if (patientZero)
patientZero.show();
break;
} }
radio.sendValue("state", state); // keep broadcasting the game state radio.sendValue("state", state); // keep broadcasting the game state
} else { // player loop } else { // player loop
switch (state) { switch (state) {
case GameState.Pairing: case GameState.Pairing:
// broadcast player id // broadcast player id
if (!icon) if (playerIcon < 0)
radio.sendValue("pair", control.deviceSerialNumber()); radio.sendValue("pair", control.deviceSerialNumber());
else if (infectedBy) else if (infectedBy > -1)
radio.sendValue("health", health); radio.sendValue("health", health);
break; break;
case GameState.Running: case GameState.Running:
@ -350,17 +372,15 @@ basic.forever(() => {
health = HealthState.Sick; health = HealthState.Sick;
// transmit disease // transmit disease
if (health == HealthState.Incubating || health == HealthState.Sick) if (health == HealthState.Incubating || health == HealthState.Sick)
radio.sendValue("transmit", icon); radio.sendValue("transmit", playerIcon);
radio.sendValue("health", health); radio.sendValue("health", health);
gameFace();
break;
case GameState.Over:
// show infection state
gameFace();
break; break;
} }
// show current animation
gameFace();
} }
}) })
basic.showIcon(IconNames.Ghost);
basic.showIcon(GameIcons.Pairing)
``` ```