From 0119f45d54fb5296131d2fe5af262e09a32641a0 Mon Sep 17 00:00:00 2001 From: "Eevee (Evelyn Woods)" Date: Mon, 1 Mar 2021 18:04:23 -0700 Subject: [PATCH] Name compat flags more consistently; add a couple; flip sliding blue tank behavior --- js/game.js | 11 ++--- js/main.js | 117 ++++++++++++++++++++++++++++++------------------ js/tiletypes.js | 28 +++++++++--- 3 files changed, 100 insertions(+), 56 deletions(-) diff --git a/js/game.js b/js/game.js index b04187c..11f88a7 100644 --- a/js/game.js +++ b/js/game.js @@ -1461,13 +1461,6 @@ export class Level extends LevelInterface { } make_actor_decision(actor, forced_only = false) { - // Compat flag for blue tanks - if (this.compat.sliding_tanks_ignore_button && - actor.slide_mode && actor.pending_reverse) - { - this._set_tile_prop(actor, 'pending_reverse', false); - } - if (actor.pending_push) { // Blocks that were pushed while sliding will move in the push direction as soon as // they can make a decision, even if they're still sliding or are off-tic. Also used @@ -2501,6 +2494,10 @@ export class Level extends LevelInterface { // Get the next direction a random force floor will use. They share global // state and cycle clockwise. get_force_floor_direction() { + if (this.compat.rff_actually_random) { + return DIRECTION_ORDER[this.prng() % 4]; + } + let d = this.force_floor_direction; this.force_floor_direction = DIRECTIONS[d].right; return d; diff --git a/js/main.js b/js/main.js index c25f0d0..b88e27e 100644 --- a/js/main.js +++ b/js/main.js @@ -2944,73 +2944,102 @@ const COMPAT_RULESETS = [ ['ms', "Microsoft"], ['custom', "Custom"], ]; -const COMPAT_FLAGS = [{ +// FIXME some of the names of the flags themselves kinda suck +const COMPAT_FLAGS = [ +// Level loading +{ key: 'no_auto_convert_ccl_popwalls', - label: "Don't fix populated recessed walls in CC1 levels", + label: "Recessed walls under actors in CCL levels are left alone", rulesets: new Set(['steam-strict', 'lynx', 'ms']), }, { key: 'no_auto_convert_ccl_blue_walls', - label: "Don't fix populated blue walls in CC1 levels", + label: "Blue walls under blocks in CCL levels are left alone", rulesets: new Set(['steam-strict', 'lynx']), +}, + +// Core +{ + key: 'use_lynx_loop', + label: "Game uses the Lynx-style update loop", + rulesets: new Set(['steam', 'steam-strict', 'lynx', 'ms']), }, { + key: 'emulate_60fps', + label: "Game runs at 60 FPS", + rulesets: new Set(['steam', 'steam-strict']), +}, + +// Tiles +{ + // XXX this is goofy + key: 'tiles_react_instantly', + label: "Tiles react when approached", + rulesets: new Set(['ms']), +}, { + key: 'rff_actually_random', + label: "Random force floors are actually random", + rulesets: new Set(['ms']), +}, + +// Items +{ key: 'no_immediate_detonate_bombs', - label: "Don't immediately detonate populated mines", + label: "Mines under non-player actors don't explode at level start", rulesets: new Set(['lynx', 'ms']), }, { key: 'detonate_bombs_under_players', - label: "Detonate mines populated by players", + label: "Mines under players explode at level start", rulesets: new Set(['steam', 'steam-strict']), }, { - key: 'tanks_teeth_push_ice_blocks', - label: "Blue tanks and teeth can push ice blocks", + key: 'monsters_ignore_keys', + label: "Monsters completely ignore keys", rulesets: new Set(['ms']), -}, { - key: 'sliding_tanks_ignore_button', - label: "Blue tanks ignore blue buttons while sliding", - // TODO ms? - rulesets: new Set(['lynx']), -}, { - key: 'cloner_tanks_react_button', - label: "Blue tanks on cloners respond to blue buttons", - rulesets: new Set(['steam-strict']), +}, + +// Blocks +{ + key: 'no_early_push', + label: "Player pushes blocks at move time", + rulesets: new Set(['lynx', 'ms']), }, { key: 'use_legacy_hooking', - label: "Player pulls blocks at decision time", - // TODO maybe steam as well? - rulesets: new Set(['steam-strict']), + label: "Pulling blocks with the hook happens at decision time", + rulesets: new Set(['steam', 'steam-strict']), }, { - key: 'monsters_ignore_keys', - label: "Monsters ignore keys", - rulesets: new Set(['ms']), -}, { - // XXX this is goofy - key: 'tiles_react_instantly', - label: "Tiles react instantly", + // FIXME this is kind of annoying, there are some collision rules too + key: 'tanks_teeth_push_ice_blocks', + label: "Ice blocks emulate pgchip rules", rulesets: new Set(['ms']), }, { key: 'emulate_spring_mining', - label: "Emulate spring mining", + label: "Spring mining is possible", + rulesets: new Set(['steam-strict']), +/* XXX not implemented +}, { + key: 'emulate_flicking', + label: "Flicking is possible", + rulesets: new Set(['ms']), +*/ +}, + +// Monsters +{ + // TODO? in lynx they ignore the button while in motion too + // TODO what about in a trap, in every game?? + // TODO what does ms do when a tank is on ice or a ff? wiki's description is wacky + // TODO yellow tanks seem to have memory too?? + key: 'tanks_always_obey_button', + label: "Blue tanks always obey blue buttons", rulesets: new Set(['steam-strict']), }, { - // XXX not implemented - /* - key: 'emulate_flicking', - label: "Emulate flicking", + key: 'rff_blocks_monsters', + label: "Random force floors block monsters", rulesets: new Set(['ms']), }, { - */ - key: 'use_lynx_loop', - label: "Use Lynx-style update loop", - rulesets: new Set(['steam', 'steam-strict', 'lynx', 'ms']), -}, { - key: 'no_early_push', - label: "Player doesn't push at decision time", - rulesets: new Set(['lynx', 'ms']), -}, { - key: 'emulate_60fps', - label: "Run at 60 FPS", - rulesets: new Set(['steam', 'steam-strict']), -}]; + key: 'fire_allows_monsters', + label: "Fire doesn't block monsters", + rulesets: new Set(['ms']), +}, +]; class CompatOverlay extends DialogOverlay { constructor(conductor) { super(conductor); diff --git a/js/tiletypes.js b/js/tiletypes.js index d5f2bf0..0283b54 100644 --- a/js/tiletypes.js +++ b/js/tiletypes.js @@ -372,6 +372,7 @@ const TILE_TYPES = { { // Blocks can be pushed off of blue walls in TW Lynx, which only works due to a tiny // quirk of the engine that I don't want to replicate, so replace them with popwalls + // TODO this also works with invis walls apparently. maybe only for blocks? me.type = TILE_TYPES['popwall']; } }, @@ -741,7 +742,15 @@ const TILE_TYPES = { // Hazards fire: { layer: LAYERS.terrain, - blocks_collision: COLLISION.monster_solid & ~COLLISION.fireball, + // Fire blocks most monsters, except in MS where they walk right in and get roasted + blocks(me, level, other) { + if (other.type.collision_mask & (COLLISION.fireball | COLLISION.ghost)) + return false; + if (other.type.collision_mask & COLLISION.monster_any) { + return ! level.compat.fire_allows_monsters; + } + return false; + }, on_arrive(me, level, other) { if (other.type.name === 'ghost') { // Ghosts with fire boots erase fire, otherwise are unaffected @@ -986,6 +995,10 @@ const TILE_TYPES = { speed_factor: 2, on_begin: on_begin_force_floor, // TODO ms: this is random, and an acting wall to monsters (!) + blocks(me, level, other) { + return (level.compat.rff_blocks_monsters && + (other.type.collision_mask & COLLISION.monster_general)); + }, on_arrive(me, level, other) { level.set_actor_direction(other, level.get_force_floor_direction()); }, @@ -1871,11 +1884,16 @@ const TILE_TYPES = { // Flip direction of all blue tanks for (let actor of level.actors) { // TODO generify somehow?? - if (actor.type.name === 'tank_blue') { - if (level.compat.cloner_tanks_react_button || ! actor.cell.has('cloner')) { - level._set_tile_prop(actor, 'pending_reverse', ! actor.pending_reverse); - } + if (actor.type.name !== 'tank_blue') + continue; + + if (! level.compat.tanks_always_obey_button && + (actor.slide_mode || actor.cell.has('cloner'))) + { + continue; } + + level._set_tile_prop(actor, 'pending_reverse', ! actor.pending_reverse); } }, on_arrive(me, level, other) {