Stub out enough to get CC2 Lesson 4 loading

- Gender signs: implemented
- Transmogrifier: basically implemented
- Yellow tank: basically implemented
- Directional blocks: load but don't draw or behave correctly
- Floor mimic: moves at hyperspeed
- Secret eye: no effect
This commit is contained in:
Eevee (Evelyn Woods) 2020-09-14 16:03:35 -06:00
parent 54aaed73a0
commit ec41139960
3 changed files with 164 additions and 14 deletions

View File

@ -133,7 +133,7 @@ const TILE_ENCODING = {
//0x41: Open trap (unused in main levels) : //0x41: Open trap (unused in main levels) :
0x42: 'trap', 0x42: 'trap',
0x43: 'cloner', 0x43: 'cloner',
//0x44: Clone machine : Modifier required, see below 0x44: ['#mod8', 'cloner'],
0x45: 'hint', 0x45: 'hint',
0x46: 'force_floor_all', 0x46: 'force_floor_all',
// 0x47: 'button_gray', // 0x47: 'button_gray',
@ -143,7 +143,7 @@ const TILE_ENCODING = {
0x4b: ['swivel_se', 'swivel_floor'], 0x4b: ['swivel_se', 'swivel_floor'],
0x4c: ['stopwatch_bonus', '#next'], 0x4c: ['stopwatch_bonus', '#next'],
0x4d: ['stopwatch_toggle', '#next'], 0x4d: ['stopwatch_toggle', '#next'],
// 0x4e: Transmogrifier : 0x4e: ['transmogrifier'],
// 0x4f: Railroad track (Modifier required, see section below) : // 0x4f: Railroad track (Modifier required, see section below) :
0x50: ['steel'], 0x50: ['steel'],
0x51: ['dynamite', '#next'], 0x51: ['dynamite', '#next'],
@ -152,16 +152,16 @@ const TILE_ENCODING = {
// 0x57: Timid teeth : '#direction', '#next' // 0x57: Timid teeth : '#direction', '#next'
// 0x58: Explosion animation (unused in main levels) : '#direction', '#next' // 0x58: Explosion animation (unused in main levels) : '#direction', '#next'
0x59: ['hiking_boots', '#next'], 0x59: ['hiking_boots', '#next'],
// 0x5a: Male-only sign : 0x5a: ['no_player2_sign'],
// 0x5b: Female-only sign : 0x5b: ['no_player1_sign'],
// 0x5c: Inverter gate (N) : Modifier allows other gates, see below // 0x5c: Inverter gate (N) : Modifier allows other gates, see below
// 0x5e: Logic switch (ON) : // 0x5e: Logic switch (ON) :
0x5f: 'flame_jet_off', 0x5f: 'flame_jet_off',
0x60: 'flame_jet_on', 0x60: 'flame_jet_on',
0x61: 'button_orange', 0x61: 'button_orange',
// 0x62: Lightning bolt : '#next' // 0x62: Lightning bolt : '#next'
// 0x63: Yellow tank : '#direction', '#next' 0x63: ['tank_yellow', '#direction', '#next'],
// 0x64: Yellow tank button : 0x64: 'button_yellow',
// 0x65: Mirror Chip : '#direction', '#next' // 0x65: Mirror Chip : '#direction', '#next'
// 0x66: Mirror Melinda : '#direction', '#next' // 0x66: Mirror Melinda : '#direction', '#next'
// 0x68: Bowling ball : '#next' // 0x68: Bowling ball : '#next'
@ -184,8 +184,8 @@ const TILE_ENCODING = {
0x7e: ['popdown_floor'], 0x7e: ['popdown_floor'],
0x7f: ['forbidden', '#next'], 0x7f: ['forbidden', '#next'],
0x80: ['score_2x', '#next'], 0x80: ['score_2x', '#next'],
// 0x81: Directional block : '#direction', Directional Arrows Bitmask, '#next' 0x81: ['directional_block', '#direction', '#directional_block_mask', '#next'],
// 0x82: Floor mimic : '#direction', '#next' 0x82: ['floor_mimic', '#direction', '#next'],
0x83: ['green_bomb', '#next'], 0x83: ['green_bomb', '#next'],
0x84: ['green_chip', '#next'], 0x84: ['green_chip', '#next'],
// 0x87: Black button : // 0x87: Black button :
@ -195,7 +195,7 @@ const TILE_ENCODING = {
// 0x8b: Ghost : '#direction', '#next' // 0x8b: Ghost : '#direction', '#next'
// 0x8c: Steel foil : '#next' // 0x8c: Steel foil : '#next'
0x8d: 'turtle', 0x8d: 'turtle',
// 0x8e: Secret eye : '#next' 0x8e: ['xray_eye', '#next'],
// 0x8f: Thief bribe : '#next' // 0x8f: Thief bribe : '#next'
// 0x90: Speed boots : '#next' // 0x90: Speed boots : '#next'
// 0x92: Hook : '#next' // 0x92: Hook : '#next'
@ -476,6 +476,25 @@ export function parse_level(buf) {
else if (arg === '#next') { else if (arg === '#next') {
has_next = true; has_next = true;
} }
else if (arg === '#directional_block_mask') {
// Direction mask used specifically for the directional block
let mask = bytes[p];
p++;
let arrows = new Set;
if (mask & 0x01) {
arrows.add('north');
}
if (mask & 0x02) {
arrows.add('east');
}
if (mask & 0x04) {
arrows.add('south');
}
if (mask & 0x08) {
arrows.add('west');
}
tile.directional_block_arrows = arrows;
}
else { else {
// Anything else is an implicit next tile, e.g. // Anything else is an implicit next tile, e.g.
// turtles imply water underneath // turtles imply water underneath

View File

@ -90,7 +90,8 @@ export const CC2_TILESET_LAYOUT = {
popdown_floor: [12, 5], popdown_floor: [12, 5],
popdown_floor_visible: [13, 5], popdown_floor_visible: [13, 5],
forbidden: [14, 5], forbidden: [14, 5],
// directional block frame, i think? // TODO arrows overlay at [3, 10]
directional_block: [15, 5],
flippers: [0, 6], flippers: [0, 6],
fire_boots: [1, 6], fire_boots: [1, 6],
@ -215,7 +216,7 @@ export const CC2_TILESET_LAYOUT = {
blob: [0, 15], blob: [0, 15],
// TODO blob animations also span multiple tiles // TODO blob animations also span multiple tiles
// TODO [0, 16] some kinda red/blue outline // TODO [0, 16] some kinda red/blue outline
mimic: [14, 16], floor_mimic: [0, 2], // TODO [14, 16] with xray
// TODO [15, 16] some kinda yellow/black outline // TODO [15, 16] some kinda yellow/black outline
// timid teeth // timid teeth
@ -228,7 +229,7 @@ export const CC2_TILESET_LAYOUT = {
}, },
// TODO saucer, has layers and moves and stuff // TODO saucer, has layers and moves and stuff
eyeball: [11, 18], xray_eye: [11, 18],
ghost: { ghost: {
north: [12, 18], north: [12, 18],
east: [13, 18], east: [13, 18],
@ -242,7 +243,7 @@ export const CC2_TILESET_LAYOUT = {
force_floor_w: [[2, 20], [3, 20]], force_floor_w: [[2, 20], [3, 20]],
teleport_green: [[4, 19], [5, 19], [6, 19], [7, 19]], teleport_green: [[4, 19], [5, 19], [6, 19], [7, 19]],
teleport_yellow: [[8, 19], [9, 19], [10, 19], [11, 19]], teleport_yellow: [[8, 19], [9, 19], [10, 19], [11, 19]],
// TODO round, thing, not sure what transmogrifier: [[12, 19], [13, 19], [14, 19], [15, 19]],
teleport_red: [[4, 20], [5, 20], [6, 20], [7, 20]], teleport_red: [[4, 20], [5, 20], [6, 20], [7, 20]],
slime: [[8, 20], [9, 20], [10, 20], [11, 20], [12, 20], [13, 20], [14, 20], [15, 20]], slime: [[8, 20], [9, 20], [10, 20], [11, 20], [12, 20], [13, 20], [14, 20], [15, 20]],
@ -300,6 +301,8 @@ export const CC2_TILESET_LAYOUT = {
// train tracks, which are layered... // train tracks, which are layered...
dirt: [4, 31], dirt: [4, 31],
no_player2_sign: [5, 31],
no_player1_sign: [6, 31],
// misc other stuff // misc other stuff
}; };

View File

@ -7,6 +7,7 @@ const LAYER_ACTOR = 2;
const LAYER_OVERLAY = 3; const LAYER_OVERLAY = 3;
// TODO cc2 order is: swivel, thinwalls, canopy (and yes you can have them all in the same tile) // TODO cc2 order is: swivel, thinwalls, canopy (and yes you can have them all in the same tile)
// TODO get rid of mentions of 'modifier' here, put them in the c2m loader
const TILE_TYPES = { const TILE_TYPES = {
// Floors and walls // Floors and walls
floor: { floor: {
@ -111,6 +112,7 @@ const TILE_TYPES = {
}, },
popdown_floor: { popdown_floor: {
draw_layer: LAYER_TERRAIN, draw_layer: LAYER_TERRAIN,
blocks_blocks: true,
// FIXME should be on_approach // FIXME should be on_approach
on_arrive(me, level, other) { on_arrive(me, level, other) {
// FIXME could probably do this with state? or, eh // FIXME could probably do this with state? or, eh
@ -119,11 +121,25 @@ const TILE_TYPES = {
}, },
popdown_floor_visible: { popdown_floor_visible: {
draw_layer: LAYER_TERRAIN, draw_layer: LAYER_TERRAIN,
blocks_blocks: true,
on_depart(me, level, other) { on_depart(me, level, other) {
// FIXME possibly changes back too fast, not even visible for a tic for me (much like stepping on a button oops) // FIXME possibly changes back too fast, not even visible for a tic for me (much like stepping on a button oops)
level.transmute_tile(me, 'popdown_floor'); level.transmute_tile(me, 'popdown_floor');
}, },
}, },
// TODO these also block the corresponding mirror actors
no_player1_sign: {
draw_layer: LAYER_TERRAIN,
blocks(me, level, other) {
return (other.type.name === 'player');
},
},
no_player2_sign: {
draw_layer: LAYER_TERRAIN,
blocks(me, level, other) {
return (other.type.name === 'player2');
},
},
steel: { steel: {
draw_layer: LAYER_TERRAIN, draw_layer: LAYER_TERRAIN,
blocks_all: true, blocks_all: true,
@ -482,6 +498,28 @@ const TILE_TYPES = {
movement_speed: 4, movement_speed: 4,
pushes: { pushes: {
ice_block: true, ice_block: true,
directional_block: true,
},
},
directional_block: {
// TODO directional, obviously
// TODO floor in water
// TODO destroyed in fire, flame jet, slime
// TODO rotate on train tracks
draw_layer: LAYER_ACTOR,
blocks_all: true,
is_actor: true,
is_block: true,
load(me, template) {
me.arrows = template.directional_block_arrows;
},
ignores: new Set(['fire']),
movement_speed: 4,
pushes: {
dirt_block: true,
clone_block: true,
ice_block: true,
directional_block: true,
}, },
}, },
green_floor: { green_floor: {
@ -519,7 +557,12 @@ const TILE_TYPES = {
}, },
cloner: { cloner: {
draw_layer: LAYER_TERRAIN, draw_layer: LAYER_TERRAIN,
// TODO not the case for an empty one in cc2, apparently
blocks_all: true, blocks_all: true,
load(me, template) {
// FIXME not actually right, this is a bitmask
me.clone_direction = template.modifier;
},
activate(me, level) { activate(me, level) {
let cell = me.cell; let cell = me.cell;
// Copy, so we don't end up repeatedly cloning the same object // Copy, so we don't end up repeatedly cloning the same object
@ -554,6 +597,44 @@ const TILE_TYPES = {
} }
}, },
}, },
transmogrifier: {
draw_layer: LAYER_TERRAIN,
_mogrifications: {
player: 'player2',
player2: 'player',
// TODO mirror players too
dirt_block: 'ice_block',
clone_block: 'ice_block',
ice_block: 'dirt_block',
ball: 'walker',
walker: 'ball',
fireball: 'bug',
bug: 'glider',
glider: 'paramecium',
paramecium: 'fireball',
tank_blue: 'tank_yellow',
tank_yellow: 'tank_blue',
// TODO teeth, timid teeth
},
_blob_mogrifications: ['ball', 'walker', 'fireball', 'glider', 'paramecium', 'bug', 'tank_blue', 'teeth', /* TODO 'timid_teeth' */ ],
// TODO can be wired, in which case only works when powered; other minor concerns, see wiki
on_arrive(me, level, other) {
let name = other.type.name;
if (me.type._mogrifications[name]) {
level.transmute_tile(other, me.type._mogrifications[name]);
}
else if (name === 'blob') {
// TODO how is this randomness determined? important for replays!
let options = me.type._blob_mogrifications;
level.transmute_tile(other, options[Math.floor(Math.random() * options.length)]);
}
},
},
teleport_blue: { teleport_blue: {
draw_layer: LAYER_TERRAIN, draw_layer: LAYER_TERRAIN,
connects_to: 'teleport_blue', connects_to: 'teleport_blue',
@ -592,7 +673,7 @@ const TILE_TYPES = {
button_blue: { button_blue: {
draw_layer: LAYER_TERRAIN, draw_layer: LAYER_TERRAIN,
on_arrive(me, level, other) { on_arrive(me, level, other) {
// Flip direction of all 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') {
@ -601,6 +682,19 @@ const TILE_TYPES = {
} }
}, },
}, },
button_yellow: {
draw_layer: LAYER_TERRAIN,
on_arrive(me, level, other) {
// Move all yellow tanks one tile in the direction of the pressing actor
for (let actor of level.actors) {
// TODO generify somehow??
if (actor.type.name === 'tank_yellow') {
level.set_actor_direction(actor, other.direction);
level.attempt_step(actor, other.direction);
}
}
},
},
button_green: { button_green: {
draw_layer: LAYER_TERRAIN, draw_layer: LAYER_TERRAIN,
on_arrive(me, level, other) { on_arrive(me, level, other) {
@ -753,6 +847,20 @@ const TILE_TYPES = {
movement_mode: 'forward', movement_mode: 'forward',
movement_speed: 4, movement_speed: 4,
}, },
tank_yellow: {
draw_layer: LAYER_ACTOR,
is_actor: true,
is_monster: true,
blocks_monsters: true,
blocks_blocks: true,
pushes: {
dirt_block: true,
clone_block: true,
ice_block: true,
directional_block: true,
},
movement_speed: 4,
},
blob: { blob: {
draw_layer: LAYER_ACTOR, draw_layer: LAYER_ACTOR,
is_actor: true, is_actor: true,
@ -792,6 +900,17 @@ const TILE_TYPES = {
movement_speed: 4, movement_speed: 4,
ignores: new Set(['water']), ignores: new Set(['water']),
}, },
floor_mimic: {
draw_layer: LAYER_ACTOR,
is_actor: true,
is_monster: true,
blocks_monsters: true,
blocks_blocks: true,
// TODO not like teeth; always pursues
// TODO takes 3 turns off!
movement_mode: 'pursue',
movement_speed: 4,
},
// Keys // Keys
// Note that red and blue keys do NOT block monsters, but yellow and green DO // Note that red and blue keys do NOT block monsters, but yellow and green DO
@ -876,6 +995,13 @@ const TILE_TYPES = {
blocks_blocks: true, blocks_blocks: true,
// FIXME does a thing when dropped, but that isn't implemented at all yet // FIXME does a thing when dropped, but that isn't implemented at all yet
}, },
xray_eye: {
draw_layer: LAYER_ITEM,
is_item: true,
is_tool: true,
blocks_monsters: true,
blocks_blocks: true,
},
// Progression // Progression
player: { player: {
@ -888,6 +1014,7 @@ const TILE_TYPES = {
dirt_block: true, dirt_block: true,
clone_block: true, clone_block: true,
ice_block: true, ice_block: true,
directional_block: true,
}, },
infinite_items: { infinite_items: {
key_green: true, key_green: true,
@ -904,6 +1031,7 @@ const TILE_TYPES = {
dirt_block: true, dirt_block: true,
clone_block: true, clone_block: true,
ice_block: true, ice_block: true,
directional_block: true,
}, },
infinite_items: { infinite_items: {
key_yellow: true, key_yellow: true,