Skip to content

Commit 6ce71bc

Browse files
authored
feature: duel mode (1 vs 1) (#38)
1 parent 768b6fd commit 6ce71bc

File tree

11 files changed

+67
-26
lines changed

11 files changed

+67
-26
lines changed

generated/schema.graphql

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1116,7 +1116,7 @@ enum e_lobby_access_enum {
11161116
"""Invite Only"""
11171117
Invite
11181118

1119-
"""Open"""
1119+
"""Public"""
11201120
Open
11211121

11221122
"""Private"""
@@ -1474,6 +1474,9 @@ enum e_map_pool_types_enum {
14741474
"""Custom match"""
14751475
Custom
14761476

1477+
"""1 vs 1 match"""
1478+
Duel
1479+
14771480
"""2 vs 2 match"""
14781481
Wingman
14791482
}
@@ -2180,6 +2183,9 @@ enum e_match_types_enum {
21802183
"""5 vs 5 match using active map pool"""
21812184
Competitive
21822185

2186+
"""1 vs 1 match"""
2187+
Duel
2188+
21832189
"""2 vs 2 match"""
21842190
Wingman
21852191
}

generated/schema.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ export interface e_map_pool_types_aggregate_fields {
557557
/** unique or primary key constraints on table "e_map_pool_types" */
558558
export type e_map_pool_types_constraint = 'e_map_pool_types_pkey'
559559

560-
export type e_map_pool_types_enum = 'Competitive' | 'Custom' | 'Wingman'
560+
export type e_map_pool_types_enum = 'Competitive' | 'Custom' | 'Duel' | 'Wingman'
561561

562562

563563
/** aggregate max on columns */
@@ -764,7 +764,7 @@ export interface e_match_types_aggregate_fields {
764764
/** unique or primary key constraints on table "e_match_types" */
765765
export type e_match_types_constraint = 'e_match_types_pkey'
766766

767-
export type e_match_types_enum = 'Competitive' | 'Wingman'
767+
export type e_match_types_enum = 'Competitive' | 'Duel' | 'Wingman'
768768

769769

770770
/** aggregate max on columns */
@@ -38679,6 +38679,7 @@ export const enumEMapPoolTypesConstraint = {
3867938679
export const enumEMapPoolTypesEnum = {
3868038680
Competitive: 'Competitive' as const,
3868138681
Custom: 'Custom' as const,
38682+
Duel: 'Duel' as const,
3868238683
Wingman: 'Wingman' as const
3868338684
}
3868438685

@@ -38751,6 +38752,7 @@ export const enumEMatchTypesConstraint = {
3875138752

3875238753
export const enumEMatchTypesEnum = {
3875338754
Competitive: 'Competitive' as const,
38755+
Duel: 'Duel' as const,
3875438756
Wingman: 'Wingman' as const
3875538757
}
3875638758

hasura/enums/maps.sql

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
insert into e_match_types ("value", "description") values
22
('Competitive', '5 vs 5 match using active map pool'),
3-
('Wingman', '2 vs 2 match')
3+
('Wingman', '2 vs 2 match'),
4+
('Duel', '1 vs 1 match')
45
on conflict(value) do update set "description" = EXCLUDED."description";
56

67
insert into maps ("name", "type", "active_pool", "workshop_map_id", "poster", "patch") values
@@ -41,38 +42,52 @@ insert into maps ("name", "type", "active_pool", "workshop_map_id", "poster", "p
4142
('de_nuke', 'Wingman', 'true', null, '/img/maps/screenshots/de_nuke.webp', '/img/maps/icons/de_nuke.svg'),
4243
('de_overpass', 'Wingman', 'true', null, '/img/maps/screenshots/de_overpass.webp', '/img/maps/icons/de_overpass.svg'),
4344
('de_vertigo', 'Wingman', 'true', null, '/img/maps/screenshots/de_vertigo.webp', '/img/maps/icons/de_vertigo.svg'),
44-
('de_assembly', 'Wingman', 'true', '3071005299', '/img/maps/screenshots/de_assembly.webp', '/img/maps/icons/de_assembly.svg'),
45-
('de_memento', 'Wingman', 'true', '3165559377', '/img/maps/screenshots/de_memento.webp', '/img/maps/icons/de_memento.svg'),
46-
('de_palais', 'Wingman', 'false', null, '/img/maps/screenshots/de_palais.webp', '/img/maps/icons/de_palais.svg'),
47-
('de_whistle', 'Wingman', 'false', null, '/img/maps/screenshots/de_whistle.webp', '/img/maps/icons/de_whistle.svg'),
45+
('de_assembly', 'Wingman', 'false', '3071005299', '/img/maps/screenshots/de_assembly.webp', '/img/maps/icons/de_assembly.svg'),
46+
('de_memento', 'Wingman', 'false', '3165559377', '/img/maps/screenshots/de_memento.webp', '/img/maps/icons/de_memento.svg'),
47+
('de_palais', 'Wingman', 'true', null, '/img/maps/screenshots/de_palais.webp', '/img/maps/icons/de_palais.svg'),
48+
('de_whistle', 'Wingman', 'true', null, '/img/maps/screenshots/de_whistle.webp', '/img/maps/icons/de_whistle.svg'),
4849

4950
-- Workshop Wingman
5051
('de_brewery', 'Wingman', 'false', '3070290240', '/img/maps/screenshots/de_brewery.webp', '/img/maps/icons/de_brewery.svg'),
5152
('drawbridge', 'Wingman', 'false', '3070192462', '/img/maps/screenshots/de_drawbridge.webp', null),
5253
('de_foroglio', 'Wingman', 'false', '3132854332', '/img/maps/screenshots/de_foroglio.webp', null),
5354
('de_overpass_night', 'Wingman', 'false', '3285124923', '/img/maps/screenshots/de_overpass_night.webp', null),
54-
('de_inferno_night', 'Wingman', 'false', '3124567099', '/img/maps/screenshots/de_inferno_night.webp', null)
55+
('de_inferno_night', 'Wingman', 'false', '3124567099', '/img/maps/screenshots/de_inferno_night.webp', null),
56+
57+
-- Valve Wingman
58+
('de_inferno', 'Duel', 'true', null, '/img/maps/screenshots/de_inferno.webp', '/img/maps/icons/de_inferno.svg'),
59+
('de_nuke', 'Duel', 'true', null, '/img/maps/screenshots/de_nuke.webp', '/img/maps/icons/de_nuke.svg'),
60+
('de_overpass', 'Duel', 'true', null, '/img/maps/screenshots/de_overpass.webp', '/img/maps/icons/de_overpass.svg'),
61+
('de_vertigo', 'Duel', 'true', null, '/img/maps/screenshots/de_vertigo.webp', '/img/maps/icons/de_vertigo.svg'),
62+
('de_assembly', 'Duel', 'false', '3071005299', '/img/maps/screenshots/de_assembly.webp', '/img/maps/icons/de_assembly.svg'),
63+
('de_memento', 'Duel', 'false', '3165559377', '/img/maps/screenshots/de_memento.webp', '/img/maps/icons/de_memento.svg'),
64+
('de_palais', 'Duel', 'true', null, '/img/maps/screenshots/de_palais.webp', '/img/maps/icons/de_palais.svg'),
65+
('de_whistle', 'Duel', 'true', null, '/img/maps/screenshots/de_whistle.webp', '/img/maps/icons/de_whistle.svg'),
66+
67+
-- Workshop Wingman
68+
('de_brewery', 'Duel', 'false', '3070290240', '/img/maps/screenshots/de_brewery.webp', '/img/maps/icons/de_brewery.svg'),
69+
('drawbridge', 'Duel', 'false', '3070192462', '/img/maps/screenshots/de_drawbridge.webp', null),
70+
('de_foroglio', 'Duel', 'false', '3132854332', '/img/maps/screenshots/de_foroglio.webp', null),
71+
('de_overpass_night', 'Duel', 'false', '3285124923', '/img/maps/screenshots/de_overpass_night.webp', null),
72+
('de_inferno_night', 'Duel', 'false', '3124567099', '/img/maps/screenshots/de_inferno_night.webp', null)
5573

5674

5775

5876
on conflict(name, type) do update set "active_pool" = EXCLUDED."active_pool", "workshop_map_id" = EXCLUDED."workshop_map_id", "poster" = EXCLUDED."poster", "patch" = EXCLUDED."patch";
5977

60-
delete from maps where type = 'Competitive' and name = 'de_aztec';
61-
delete from maps where type = 'Competitive' and name = 'de_cpl_mill';
62-
delete from maps where type = 'Competitive' and name = 'drawbridge';
63-
delete from maps where type = 'Wingman' and name = 'de_train';
64-
6578
insert into e_map_pool_types ("value", "description") values
6679
('Competitive', '5 vs 5 match using active map pool'),
6780
('Wingman', '2 vs 2 match'),
81+
('Duel', '1 vs 1 match'),
6882
('Custom', 'Custom match')
6983
on conflict(value) do update set "description" = EXCLUDED."description";
7084

7185
WITH new_rows AS (
7286
SELECT *
7387
FROM (VALUES
7488
('Competitive', true, true),
75-
('Wingman', true, true)
89+
('Wingman', true, true),
90+
('Duel', true, true)
7691
) AS data(type, enabled, seed)
7792
)
7893
INSERT INTO map_pools ("type", "enabled", "seed")
@@ -88,7 +103,7 @@ WHERE NOT EXISTS (
88103
WITH pool_ids AS (
89104
SELECT id, type
90105
FROM map_pools
91-
WHERE type IN ('Competitive', 'Wingman')
106+
WHERE type IN ('Competitive', 'Wingman', 'Duel')
92107
ORDER BY type
93108
),
94109
inserted_maps AS (
@@ -97,7 +112,8 @@ inserted_maps AS (
97112
FROM maps m
98113
JOIN pool_ids p ON (
99114
(p.type = 'Competitive' AND m.type = 'Competitive' AND m.active_pool = 'true') OR
100-
(p.type = 'Wingman' AND m.type = 'Wingman' AND m.active_pool = 'true')
115+
(p.type = 'Wingman' AND m.type = 'Wingman' AND m.active_pool = 'true') OR
116+
(p.type = 'Duel' AND m.type = 'Duel' AND m.active_pool = 'true')
101117
)
102118
ON CONFLICT DO NOTHING
103119
RETURNING *

hasura/functions/match/get_match_type_min_players.sql

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@ LANGUAGE plpgsql
44
STABLE
55
AS $$
66
BEGIN
7-
IF match_type = 'Wingman' THEN
7+
IF match_type = 'Competitive' THEN
8+
RETURN 5;
9+
ELSIF match_type = 'Wingman' THEN
810
RETURN 2;
11+
ELSIF match_type = 'Duel' THEN
12+
RETURN 1;
913
ELSE
10-
RETURN 5;
14+
RAISE EXCEPTION 'Invalid match type: %', match_type USING ERRCODE = '22000';
1115
END IF;
1216
END;
1317
$$;

src/discord-bot/discord-bot.service.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ export class DiscordBotService {
3535
maps: { name: string; id: string }[];
3636
}
3737
> = {
38-
Competitive: undefined,
38+
Duel: undefined,
3939
Wingman: undefined,
40+
Competitive: undefined,
4041
};
4142

4243
constructor(
@@ -158,6 +159,11 @@ export class DiscordBotService {
158159
.setName(ChatCommands.ScheduleWingMan)
159160
.setDescription("Creates a Wingman Match"),
160161
),
162+
await this.addBaseOptions(
163+
new SlashCommandBuilder()
164+
.setName(ChatCommands.ScheduleDuel)
165+
.setDescription("Creates a Duel Match"),
166+
),
161167
new SlashCommandBuilder()
162168
.setName(ChatCommands.LinkDiscord)
163169
.setDescription(

src/discord-bot/discord-pick-player/discord-pick-player.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ export class DiscordPickPlayerService {
223223
await this.pickMember(
224224
matchId,
225225
otherLineup.id,
226-
match.options.type === "Wingman"
226+
match.options.type != "Competitive"
227227
? 1
228228
: /**
229229
* Pick Order: 1 -> 2 -> 1 by 1
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export enum ChatCommands {
22
ScheduleComp = "competitive",
33
ScheduleWingMan = "wingman",
4+
ScheduleDuel = "duel",
45
LinkDiscord = "link",
56
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { e_match_types_enum } from "../../../generated";
22

33
export const ExpectedPlayers: Record<e_match_types_enum, number> = {
4+
["Duel"]: 2,
45
["Wingman"]: 4,
56
["Competitive"]: 10,
67
};

src/discord-bot/interactions/ScheduleMatch.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
2525

2626
@BotChatCommand(ChatCommands.ScheduleComp)
2727
@BotChatCommand(ChatCommands.ScheduleWingMan)
28+
@BotChatCommand(ChatCommands.ScheduleDuel)
2829
export default class ScheduleMatch extends DiscordInteraction {
2930
public async handler(interaction: ChatInputCommandInteraction) {
3031
let matchType: e_match_types_enum;
@@ -39,6 +40,10 @@ export default class ScheduleMatch extends DiscordInteraction {
3940
matchType = "Wingman";
4041
mapPoolType = "Wingman";
4142
break;
43+
case ChatCommands.ScheduleDuel:
44+
matchType = "Duel";
45+
mapPoolType = "Duel";
46+
break;
4247
default:
4348
throw Error(`match type not supported ${interaction.type}`);
4449
}
@@ -255,7 +260,7 @@ export default class ScheduleMatch extends DiscordInteraction {
255260
const availableUsers = usersInChannel;
256261
const shuffledUsers = availableUsers.sort(() => Math.random() - 0.5);
257262

258-
const playersPerTeam = matchType === "Wingman" ? 2 : 5;
263+
const playersPerTeam = ExpectedPlayers[matchType];
259264
for (let playerIndex = 0; playerIndex < playersPerTeam * 2; playerIndex++) {
260265
if (playerIndex < shuffledUsers.length) {
261266
const user = shuffledUsers[playerIndex];
@@ -301,7 +306,7 @@ export default class ScheduleMatch extends DiscordInteraction {
301306
options[option.name] = option.value;
302307
}
303308

304-
if (matchType === "Wingman" && options.mr === 12) {
309+
if (matchType !== "Competitive") {
305310
options.mr = 8;
306311
}
307312

src/matches/events/MatchUpdatedLineupsEvent.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { ExpectedPlayers } from "src/discord-bot/enums/ExpectedPlayers";
12
import MatchEventProcessor from "./abstracts/MatchEventProcessor";
23

34
export default class MatchUpdatedLineupsEvent extends MatchEventProcessor<{
@@ -60,9 +61,7 @@ export default class MatchUpdatedLineupsEvent extends MatchEventProcessor<{
6061
}
6162
}
6263

63-
if (match.options.type === "Competitive" && players.length < 10) {
64-
return;
65-
} else if (match.options.type === "Wingman" && players.length < 2) {
64+
if (players.length < ExpectedPlayers[match.options.type] * 2) {
6665
return;
6766
}
6867

0 commit comments

Comments
 (0)