Skip to content

Commit

Permalink
Use value rules for timer (smogon#10194)
Browse files Browse the repository at this point in the history
* Use value rules for timer

* lint

* fix rule overrides

* fix the "boolean" value rules

* add limits for number based rules

* Realized that you don't need boolean value rules

* oops

* fix checks for lower bounds
  • Loading branch information
Karthik99999 authored Sep 30, 2024
1 parent f8b048c commit 4ba7f6e
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 40 deletions.
25 changes: 5 additions & 20 deletions config/formats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3428,16 +3428,7 @@ export const Formats: import('../sim/dex-formats').FormatList = [
gameType: 'doubles',
searchShow: false,
bestOfDefault: true,
timer: {
starting: 5 * 60,
addPerTurn: 0,
maxPerTurn: 55,
maxFirstTurn: 90,
grace: 90,
timeoutAutoChoose: true,
dcTimerBank: false,
},
ruleset: ['Flat Rules', '!! Adjust Level = 50', 'Min Source Gen = 7'],
ruleset: ['Flat Rules', '!! Adjust Level = 50', 'Min Source Gen = 7', 'VGC Timer', '!! Timer Starting = 300'],
banlist: ['Oranguru + Symbiosis', 'Passimian + Defiant', 'Unown', 'Custap Berry', 'Enigma Berry', 'Jaboca Berry', 'Micle Berry', 'Rowap Berry', 'Battle Bond'],
},
{
Expand All @@ -3446,16 +3437,10 @@ export const Formats: import('../sim/dex-formats').FormatList = [
gameType: 'doubles',
searchShow: false,
bestOfDefault: true,
timer: {
starting: 15 * 60,
addPerTurn: 0,
maxPerTurn: 55,
maxFirstTurn: 90,
grace: 90,
timeoutAutoChoose: true,
dcTimerBank: false,
},
ruleset: ['Flat Rules', 'Old Alola Pokedex', '!! Adjust Level = 50', 'Min Source Gen = 7'],
ruleset: [
'Flat Rules', 'Old Alola Pokedex', '!! Adjust Level = 50', 'Min Source Gen = 7',
'VGC Timer', '!! Timer Starting = 900',
],
banlist: ['Mega', 'Custap Berry', 'Enigma Berry', 'Jaboca Berry', 'Micle Berry', 'Rowap Berry'],
},
{
Expand Down
75 changes: 69 additions & 6 deletions data/rulesets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -690,25 +690,88 @@ export const Rulesets: import('../sim/dex-formats').FormatDataTable = {
}
},
},
timerstarting: {
effectType: 'Rule',
name: 'Timer Starting',
desc: "Amount of time given at the start of the battle in seconds",
hasValue: 'positive-integer',
// hardcoded in server/room-battle.ts
},
dctimer: {
effectType: 'Rule',
name: 'DC Timer',
desc: "Enables or disables the disconnection timer",
// hardcoded in server/room-battle.ts
},
dctimerbank: {
effectType: 'Rule',
name: 'DC Timer Bank',
desc: "Enables or disables the disconnection timer bank",
// hardcoded in server/room-battle.ts
},
timergrace: {
effectType: 'Rule',
name: 'Timer Grace',
desc: "Grace period between timer activation and when total time starts ticking down.",
hasValue: 'positive-integer',
// hardcoded in server/room-battle.ts
},
timeraddperturn: {
effectType: 'Rule',
name: 'Timer Add Per Turn',
desc: "Amount of additional time given per turn in seconds",
hasValue: 'integer',
// hardcoded in server/room-battle.ts
},
timermaxperturn: {
effectType: 'Rule',
name: 'Timer Max Per Turn',
desc: "Maximum amount of time allowed per turn in seconds",
hasValue: 'positive-integer',
// hardcoded in server/room-battle.ts
},
timermaxfirstturn: {
effectType: 'Rule',
name: 'Timer Max First Turn',
desc: "Maximum amount of time allowed for the first turn in seconds",
hasValue: 'positive-integer',
// hardcoded in server/room-battle.ts
},
timeoutautochoose: {
effectType: 'Rule',
name: 'Timeout Auto Choose',
desc: "Enables or disables automatic selection of moves when a player times out",
// hardcoded in server/room-battle.ts
},
timeraccelerate: {
effectType: 'Rule',
name: 'Timer Accelerate',
desc: "Enables or disables timer acceleration",
// hardcoded in server/room-battle.ts
},
blitz: {
effectType: 'Rule',
name: 'Blitz',
// THIS 100% INTENTIONALLY SAYS TEN SECONDS PER TURN
// IGNORE maxPerTurn. addPerTurn IS 5, TRANSLATING TO AN INCREMENT OF 10.
// IGNORE Max Per Turn. Add Per Turn IS 5, TRANSLATING TO AN INCREMENT OF 10.
desc: "Super-fast 'Blitz' timer giving 30 second Team Preview and 10 seconds per turn.",
onBegin() {
this.add('rule', 'Blitz: Super-fast timer');
},
timer: {starting: 15, addPerTurn: 5, maxPerTurn: 15, maxFirstTurn: 40, grace: 30},
ruleset: [
'Timer Starting = 15', 'Timer Grace = 30',
'Timer Add Per Turn = 5', 'Timer Max Per Turn = 15', 'Timer Max First Turn = 40',
],
},
vgctimer: {
effectType: 'Rule',
name: 'VGC Timer',
desc: "VGC's timer: 90 second Team Preview, 7 minutes Your Time, 1 minute per turn",
timer: {
starting: 7 * 60, addPerTurn: 0, maxPerTurn: 55, maxFirstTurn: 90,
grace: 90, timeoutAutoChoose: true, dcTimerBank: false,
},
ruleset: [
'Timer Starting = 420', 'Timer Grace = 90',
'Timer Add Per Turn = 0', 'Timer Max Per Turn = 55', 'Timer Max First Turn = 90',
'Timeout Auto Choose', 'DC Timer Bank',
],
},
speciesclause: {
effectType: 'ValidatorRule',
Expand Down
5 changes: 3 additions & 2 deletions server/room-battle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,10 @@ export class RoomBattleTimer {
this.lastDisabledTime = 0;
this.lastDisabledByUser = null;

const hasLongTurns = Dex.formats.get(battle.format, true).gameType !== 'singles';
const format = Dex.formats.get(battle.format, true);
const hasLongTurns = format.gameType !== 'singles';
const isChallenge = (battle.challengeType === 'challenge');
const timerEntry = Dex.formats.getRuleTable(Dex.formats.get(battle.format, true)).timer;
const timerEntry = Dex.formats.getRuleTable(format).timer;
const timerSettings = timerEntry?.[0];

// so that Object.assign doesn't overwrite anything with `undefined`
Expand Down
59 changes: 47 additions & 12 deletions sim/dex-formats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,36 @@ export class RuleTable extends Map<string, string> {
this.evLimit = Number(this.valueRules.get('evlimit'));
if (isNaN(this.evLimit)) this.evLimit = null;

const timer: Partial<GameTimerSettings> = {};
if (this.valueRules.has('timerstarting')) {
timer.starting = Number(this.valueRules.get('timerstarting'));
}
if (this.has('dctimer')) {
timer.dcTimer = true;
}
if (this.has('dctimerbank')) {
timer.dcTimer = true;
}
if (this.valueRules.has('timergrace')) {
timer.grace = Number(this.valueRules.get('timergrace'));
}
if (this.valueRules.has('timeraddperturn')) {
timer.addPerTurn = Number(this.valueRules.get('timeraddperturn'));
}
if (this.valueRules.has('timermaxperturn')) {
timer.maxPerTurn = Number(this.valueRules.get('timermaxperturn'));
}
if (this.valueRules.has('timermaxfirstturn')) {
timer.maxFirstTurn = Number(this.valueRules.get('timermaxfirstturn'));
}
if (this.has('timeoutautochoose')) {
timer.timeoutAutoChoose = true;
}
if (this.has('timeraccelerate')) {
timer.accelerate = true;
}
if (Object.keys(timer).length) this.timer = [timer, format.name];

if (this.valueRules.get('pickedteamsize') === 'Auto') {
this.pickedTeamSize = (
['doubles', 'rotation'].includes(format.gameType) ? 4 :
Expand Down Expand Up @@ -311,6 +341,22 @@ export class RuleTable extends Map<string, string> {
throw new Error(`EV Limit ${this.evLimit}${this.blame('evlimit')} can't be less than 0 (you might have meant: "! EV Limit" to remove the limit, or "EV Limit = 0" to ban EVs).`);
}

if (timer.starting !== undefined && (timer.starting < 10 || timer.starting > 1200)) {
throw new Error(`Timer starting value ${timer.starting}${this.blame('timerstarting')} must be between 10 and 1200 seconds.`);
}
if (timer.grace && timer.grace > 300) {
throw new Error(`Timer grace value ${timer.grace}${this.blame('timergrace')} must be at most 300 seconds.`);
}
if (timer.addPerTurn && timer.addPerTurn > 30) {
throw new Error(`Timer add per turn value ${timer.addPerTurn}${this.blame('timeraddperturn')} must be at most 30 seconds.`);
}
if (timer.maxPerTurn !== undefined && (timer.maxPerTurn < 10 || timer.maxPerTurn > 1200)) {
throw new Error(`Timer max per turn value ${timer.maxPerTurn}${this.blame('timermaxperturn')} must be between 10 and 1200 seconds.`);
}
if (timer.maxFirstTurn !== undefined && (timer.maxFirstTurn < 10 || timer.maxFirstTurn > 1200)) {
throw new Error(`Timer max first turn value ${timer.maxFirstTurn}${this.blame('timermaxfirstturn')} must be between 10 and 1200 seconds.`);
}

if ((format as any).cupLevelLimit) {
throw new Error(`cupLevelLimit.range[0], cupLevelLimit.range[1], cupLevelLimit.total are now rules, respectively: "Min Level = NUMBER", "Max Level = NUMBER", and "Max Total Level = NUMBER"`);
}
Expand Down Expand Up @@ -400,7 +446,6 @@ export class Format extends BasicEffect implements Readonly<BasicEffect> {
declare readonly bestOfDefault?: boolean;
declare readonly teraPreviewDefault?: boolean;
declare readonly threads?: string[];
declare readonly timer?: Partial<GameTimerSettings>;
declare readonly tournamentShow?: boolean;
declare readonly checkCanLearn?: (
this: TeamValidator, move: Move, species: Species, setSources: PokemonSources, set: PokemonSet
Expand Down Expand Up @@ -678,9 +723,6 @@ export class DexFormats {
if (format.checkCanLearn) {
ruleTable.checkCanLearn = [format.checkCanLearn, format.name];
}
if (format.timer) {
ruleTable.timer = [format.timer, format.name];
}

// apply rule repeals before other rules
// repeals is a ruleid:depth map (positive: unused, negative: used)
Expand Down Expand Up @@ -752,6 +794,7 @@ export class DexFormats {
throw new Error(`In rule "${ruleSpec}", "${value}" must be positive.`);
}
}

const oldValue = ruleTable.valueRules.get(subformat.id);
if (oldValue === value) {
throw new Error(`Rule "${ruleSpec}" is redundant with existing rule "${subformat.id}=${value}"${ruleTable.blame(subformat.id)}.`);
Expand Down Expand Up @@ -827,14 +870,6 @@ export class DexFormats {
}
ruleTable.checkCanLearn = subRuleTable.checkCanLearn;
}
if (subRuleTable.timer) {
if (ruleTable.timer) {
throw new Error(
`"${format.name}" has conflicting timer validation rules from "${ruleTable.timer[1]}" and "${subRuleTable.timer[1]}"`
);
}
ruleTable.timer = subRuleTable.timer;
}
}
ruleTable.getTagRules();

Expand Down

0 comments on commit 4ba7f6e

Please sign in to comment.