Skip to content

Commit 1ee4753

Browse files
committed
Support predefined games (/sniper, /minigun)
1 parent 73e920b commit 1ee4753

5 files changed

Lines changed: 103 additions & 10 deletions

File tree

data/fights/minigun.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "Minigun Madness",
3+
"command": "minigun",
4+
"goal": "Take out your enemies with a minigun before they spot you.",
5+
6+
"settings": {
7+
"fights/location": "Acter Nuclear Power Plant",
8+
"fights/pickups": false
9+
}
10+
}

data/fights/sniper.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "Sniper Madness",
3+
"command": "sniper",
4+
"goal": "Take out your enemies while trying to remain hidden yourself.",
5+
6+
"settings": {
7+
"fights/location": "Acter Nuclear Power Plant",
8+
"fights/pickups": false
9+
}
10+
}

javascript/features/fights/fight_game.test.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,10 @@ describe('FightGame', (it, beforeEach) => {
1010
let russell = null;
1111
let settings = null;
1212

13-
beforeEach(async() => {
13+
beforeEach(async () => {
1414
const feature = server.featureManager.loadFeature('fights');
1515
const finance = server.featureManager.loadFeature('finance');
1616

17-
feature.registry_.initialize();
18-
1917
games = server.featureManager.loadFeature('games');
2018
gunther = server.playerManager.getById(/* Gunther= */ 0);
2119
russell = server.playerManager.getById(/* Russell= */ 1);
@@ -50,10 +48,10 @@ describe('FightGame', (it, beforeEach) => {
5048
}
5149

5250
it('should be able to pick random spawn positions in individual games', async (assert) => {
53-
assert.isTrue(server.commandManager.hasCommand('newfights'));
51+
assert.isTrue(server.commandManager.hasCommand('sniper'));
5452

55-
assert.isTrue(await gunther.issueCommand('/newfights'));
56-
assert.isTrue(await russell.issueCommand('/newfights'));
53+
assert.isTrue(await gunther.issueCommand('/sniper'));
54+
assert.isTrue(await russell.issueCommand('/sniper'));
5755

5856
await server.clock.advance(settings.getValue('games/registration_expiration_sec') * 1000);
5957
await runGameLoop();

javascript/features/fights/fight_registry.js

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,30 @@
22
// Use of this source code is governed by the MIT license, a copy of which can
33
// be found in the LICENSE file.
44

5+
import { CommandBuilder } from 'components/command_manager/command_builder.js';
6+
import { FightGame } from 'features/fights/fight_game.js';
57
import { FightLocationDescription } from 'features/fights/fight_location_description.js';
68
import { FightLocation } from 'features/fights/fight_location.js';
9+
import { GameCommandParams } from 'features/games/game_command_params.js';
10+
11+
import { clone } from 'base/clone.js';
12+
13+
// Directory in which the fight commands aer located.
14+
const kCommandDirectory = 'data/fights/';
715

816
// Directory in which the fight locations are located.
917
const kLocationDirectory = 'data/fights/locations/';
1018

1119
// Keeps track of the fight locations, commands and configuration available on the server. Is
1220
// responsible for loading it, and doing the initial initialization.
1321
export class FightRegistry {
22+
#commands_ = null;
23+
#games_ = null;
1424
#locations_ = null;
1525

16-
constructor() {
26+
constructor(games) {
27+
this.#commands_ = new Set();
28+
this.#games_ = games;
1729
this.#locations_ = new Map();
1830
}
1931

@@ -29,6 +41,7 @@ export class FightRegistry {
2941
// the Fights class for production usage, but has to be called manually when running tests.
3042
initialize() {
3143
this.initializeLocations();
44+
this.initializeCommands();
3245
}
3346

3447
// Initializes the locations in which fights can take place. Each is based on a structured game
@@ -42,9 +55,59 @@ export class FightRegistry {
4255
}
4356
}
4457

58+
// Initializes the commands which act as shortcuts to the available fighting game configuration,
59+
// to make it easier for players to start a game.
60+
initializeCommands() {
61+
for (const filename of glob(kCommandDirectory, '.*fights[\\\\/][^\\\\/]*\.json$')) {
62+
const configuration = JSON.parse(readFile(kCommandDirectory + filename));
63+
const settings = new Map();
64+
65+
for (const [ identifier, value ] of Object.entries(configuration.settings))
66+
settings.set(identifier, value);
67+
68+
settings.set('internal/goal', configuration.goal);
69+
settings.set('internal/name', configuration.name);
70+
71+
this.registerCommand(configuration.command, settings);
72+
}
73+
}
74+
75+
// ---------------------------------------------------------------------------------------------
76+
77+
// Registers a command with the server, following the given configuration. Activating it will
78+
// immediately start the sign-up flow of the configured game. This mimics the command syntax
79+
// that the games features exposes by default.
80+
registerCommand(command, settings) {
81+
server.commandManager.buildCommand(command)
82+
.sub('custom')
83+
.build(FightRegistry.prototype.onCommand.bind(this, settings, /* custom= */ true))
84+
.sub(CommandBuilder.NUMBER_PARAMETER)
85+
.build(FightRegistry.prototype.onCommand.bind(this, settings, /* custom= */ false))
86+
.build(FightRegistry.prototype.onCommand.bind(this, settings, /* custom= */ false));
87+
88+
this.#commands_.add(command);
89+
}
90+
91+
// Called when the |player| has issued a command. We'll construct the game command parameters
92+
// and use their API in order to formally request starting the game.
93+
onCommand(settings, customise, player, registrationId) {
94+
const params = new GameCommandParams();
95+
96+
params.customise = !!customise;
97+
params.registrationId = registrationId;
98+
params.settings = clone(settings);
99+
100+
return this.#games_().startGame(FightGame, player, params);
101+
}
102+
45103
// ---------------------------------------------------------------------------------------------
46104

47105
dispose() {
106+
for (const command of this.#commands_)
107+
server.commandManager.removeCommand(command);
108+
109+
this.#commands_ = null;
110+
48111
this.#locations_.clear();
49112
this.#locations_ = null;
50113
}

javascript/features/fights/fights.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export default class Fights extends Feature {
2727

2828
// Has knowledge of the locations and commands (+presets) of games that are available on the
2929
// server. Will be immediately initialized, even for tests.
30-
this.registry_ = new FightRegistry();
30+
this.registry_ = new FightRegistry(this.games_);
3131
this.registry_.initialize();
3232

3333
// Register all games known to this feature when the Settings feature has been loaded, as
@@ -43,14 +43,16 @@ export default class Fights extends Feature {
4343
const minimumPlayers = this.settings_().getValue('games/fight_minimum_players');
4444

4545
this.games_().registerGame(FightGame, {
46-
name: 'Deathmatch Fight',
46+
name: Fights.prototype.composeGameName.bind(this),
4747
goal: 'Defeat all other players to win the fight.',
48-
command: 'newfights',
4948

5049
minimumPlayers,
5150
maximumPlayers: 16,
5251

5352
settings: [
53+
// Option: Name (internal, string)
54+
new Setting('internal', 'name', Setting.TYPE_STRING, null, 'Display name'),
55+
5456
// Option: Location (string)
5557
new Setting(
5658
'fights', 'location', [ ...this.registry_.locations.keys() ], defaultLocation,
@@ -63,6 +65,16 @@ export default class Fights extends Feature {
6365
}, this.registry_);
6466
}
6567

68+
// Composes the display name of the fighting game that's about to be started. This should be set
69+
// in the internal values for predefined games, but will otherwise be composed of the settings
70+
// that the game is being started with.
71+
composeGameName(settings) {
72+
const base = settings.get('internal/name') ?? 'Deathmatch Fight';
73+
74+
// TODO: Specialise based on the given |settings|.
75+
return base;
76+
}
77+
6678
dispose() {
6779
this.registry_.dispose();
6880
this.registry_ = null;

0 commit comments

Comments
 (0)