Name compat flags more consistently; add a couple; flip sliding blue tank behavior

This commit is contained in:
Eevee (Evelyn Woods) 2021-03-01 18:04:23 -07:00
parent 3359c21387
commit 0119f45d54
3 changed files with 100 additions and 56 deletions

View File

@ -1461,13 +1461,6 @@ export class Level extends LevelInterface {
} }
make_actor_decision(actor, forced_only = false) { 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) { if (actor.pending_push) {
// Blocks that were pushed while sliding will move in the push direction as soon as // 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 // 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 // Get the next direction a random force floor will use. They share global
// state and cycle clockwise. // state and cycle clockwise.
get_force_floor_direction() { get_force_floor_direction() {
if (this.compat.rff_actually_random) {
return DIRECTION_ORDER[this.prng() % 4];
}
let d = this.force_floor_direction; let d = this.force_floor_direction;
this.force_floor_direction = DIRECTIONS[d].right; this.force_floor_direction = DIRECTIONS[d].right;
return d; return d;

View File

@ -2944,73 +2944,102 @@ const COMPAT_RULESETS = [
['ms', "Microsoft"], ['ms', "Microsoft"],
['custom', "Custom"], ['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', 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']), rulesets: new Set(['steam-strict', 'lynx', 'ms']),
}, { }, {
key: 'no_auto_convert_ccl_blue_walls', 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']), 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', 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']), rulesets: new Set(['lynx', 'ms']),
}, { }, {
key: 'detonate_bombs_under_players', 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']), rulesets: new Set(['steam', 'steam-strict']),
}, { }, {
key: 'tanks_teeth_push_ice_blocks', key: 'monsters_ignore_keys',
label: "Blue tanks and teeth can push ice blocks", label: "Monsters completely ignore keys",
rulesets: new Set(['ms']), rulesets: new Set(['ms']),
}, { },
key: 'sliding_tanks_ignore_button',
label: "Blue tanks ignore blue buttons while sliding", // Blocks
// TODO ms? {
rulesets: new Set(['lynx']), key: 'no_early_push',
}, { label: "Player pushes blocks at move time",
key: 'cloner_tanks_react_button', rulesets: new Set(['lynx', 'ms']),
label: "Blue tanks on cloners respond to blue buttons",
rulesets: new Set(['steam-strict']),
}, { }, {
key: 'use_legacy_hooking', key: 'use_legacy_hooking',
label: "Player pulls blocks at decision time", label: "Pulling blocks with the hook happens at decision time",
// TODO maybe steam as well? rulesets: new Set(['steam', 'steam-strict']),
rulesets: new Set(['steam-strict']),
}, { }, {
key: 'monsters_ignore_keys', // FIXME this is kind of annoying, there are some collision rules too
label: "Monsters ignore keys", key: 'tanks_teeth_push_ice_blocks',
rulesets: new Set(['ms']), label: "Ice blocks emulate pgchip rules",
}, {
// XXX this is goofy
key: 'tiles_react_instantly',
label: "Tiles react instantly",
rulesets: new Set(['ms']), rulesets: new Set(['ms']),
}, { }, {
key: 'emulate_spring_mining', 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']), rulesets: new Set(['steam-strict']),
}, { }, {
// XXX not implemented key: 'rff_blocks_monsters',
/* label: "Random force floors block monsters",
key: 'emulate_flicking',
label: "Emulate flicking",
rulesets: new Set(['ms']), rulesets: new Set(['ms']),
}, { }, {
*/ key: 'fire_allows_monsters',
key: 'use_lynx_loop', label: "Fire doesn't block monsters",
label: "Use Lynx-style update loop", rulesets: new Set(['ms']),
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']),
}];
class CompatOverlay extends DialogOverlay { class CompatOverlay extends DialogOverlay {
constructor(conductor) { constructor(conductor) {
super(conductor); super(conductor);

View File

@ -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 // 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 // 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']; me.type = TILE_TYPES['popwall'];
} }
}, },
@ -741,7 +742,15 @@ const TILE_TYPES = {
// Hazards // Hazards
fire: { fire: {
layer: LAYERS.terrain, 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) { on_arrive(me, level, other) {
if (other.type.name === 'ghost') { if (other.type.name === 'ghost') {
// Ghosts with fire boots erase fire, otherwise are unaffected // Ghosts with fire boots erase fire, otherwise are unaffected
@ -986,6 +995,10 @@ const TILE_TYPES = {
speed_factor: 2, speed_factor: 2,
on_begin: on_begin_force_floor, on_begin: on_begin_force_floor,
// TODO ms: this is random, and an acting wall to monsters (!) // 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) { on_arrive(me, level, other) {
level.set_actor_direction(other, level.get_force_floor_direction()); level.set_actor_direction(other, level.get_force_floor_direction());
}, },
@ -1871,12 +1884,17 @@ const TILE_TYPES = {
// Flip direction of all blue tanks // Flip direction of all blue tanks
for (let actor of level.actors) { for (let actor of level.actors) {
// TODO generify somehow?? // TODO generify somehow??
if (actor.type.name === 'tank_blue') { if (actor.type.name !== 'tank_blue')
if (level.compat.cloner_tanks_react_button || ! actor.cell.has('cloner')) { 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); level._set_tile_prop(actor, 'pending_reverse', ! actor.pending_reverse);
} }
}
}
}, },
on_arrive(me, level, other) { on_arrive(me, level, other) {
level.sfx.play_once('button-press', me.cell); level.sfx.play_once('button-press', me.cell);