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) {
// 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;

View File

@ -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);

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
// 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) {