diff --git a/src/Map.cc b/src/Map.cc index 6daba21e..1cdfb901 100644 --- a/src/Map.cc +++ b/src/Map.cc @@ -16,7 +16,7 @@ using namespace std; -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Set data table (variations index) string Variations::str() const { @@ -68,8 +68,7 @@ vector SetDataTableBase::map_filenames_for_variations( } std::array SetDataTableBase::default_floor_to_area(Version version, Episode episode) { - // For some inscrutable reason, Pioneer 2's area number in Episode 4 is - // discontiguous with all the rest. Why, Sega?? + // For some inscrutable reason, Pioneer 2's area number in Episode 4 is discontiguous with all the rest. Why, Sega?? static const array areas_ep1 = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11}; static const array areas_ep2_gc_nte = { @@ -571,23 +570,21 @@ static const vector>> map_file_info = { }, }; -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // DAT file structure struct DATEntityDefinition { - // This field directly maps to the base_type field in ObjectSetEntry and - // EnemySetEntry. + // This field directly maps to the base_type field in ObjectSetEntry and EnemySetEntry. uint16_t base_type; - // Each bit in this field indicates whether the definition applies to that - // version or not. Earlier versions are in less-significant bits. + // Each bit in this field indicates whether the definition applies to that version or not. Earlier versions are in + // less-significant bits. uint16_t version_flags; - // Each bit in this field indicates whether the definition applies to that - // area or not. Ep1 Pioneer 2 is the least-significant bit. Note that Episode - // 3 only has Morgue (0x1), battle (0x2), and lobby (0x8000) areas, so only - // those bits can be set here if version_flags is F_EP3. + // Each bit in this field indicates whether the definition applies to that area or not. Ep1 Pioneer 2 is the least- + // significant bit. Note that Episode 3 only has Morgue (0x1), battle (0x2), and lobby (0x8000) areas, so only those + // bits can be set here if version_flags is F_EP3. uint64_t area_flags; - // This is the internal name of the class as specified in the client, if it's - // available (if not, this is a somewhat-descriptive made-up name). + // This is the internal name of the class as specified in the client, if it's available (if not, this is a somewhat- + // descriptive made-up name). const char* name; }; @@ -607,30 +604,24 @@ static constexpr uint16_t F_EP3 = 0x0C00; static const vector dat_object_definitions({ // This is newserv's canonical list of map object types. - // Objects defined in map files take arguments in the form of an - // ObjectSetEntry structure (see Map.hh). Most objects take parameters - // only in param1-3 (floats) and param4-6 (ints), but a few of them use - // the angle fields as additional int parameters. All objects are - // available on all versions of the game (except Episode 3) unless - // otherwise noted, but most objects are available only on specific - // floors unless an omnispawn patch is used. + // Objects defined in map files take arguments in the form of an ObjectSetEntry structure (see Map.hh). Most + // objects take parameters only in param1-3 (floats) and param4-6 (ints), but a few of them use the angle fields as + // additional int parameters. All objects are available on all versions of the game (except Episode 3) unless + // otherwise noted, but most objects are available only on specific floors unless an omnispawn patch is used. // Defines where a player should start when entering a floor. Params: // param1 = client ID // param4 = source type: // 0 = use this set when advancing from a lower floor // 1 = use this set when returning from a higher floor - // anything else = set is unused (TODO: but maybe used by - // TObjAreaWarpQuest?) + // anything else = set is unused (TODO: but maybe used by TObjAreaWarpQuest?) {0x0000, F_V0_V4, 0x00007FFFFFFFFFFF, "TObjPlayerSet"}, {0x0000, F_EP3, 0x0000000000008001, "TObjPlayerSet"}, - // Displays a particle effect. This object is not constructed in - // split-screen mode. Params: + // Displays a particle effect. This object is not constructed in split-screen mode. Params: // param1 = particle type (truncated to int, clamped to nonnegative) // param3 = TODO - // param4 = if equal to 1, increase draw distance from 200 to 1500; if - // any other value, no effect + // param4 = if equal to 1, increase draw distance from 200 to 1500; if any other value, no effect // param5 = TODO // param6 = TODO {0x0001, F_V0_V4, 0x00006FFFFFFFFFFF, "TObjParticle"}, @@ -638,23 +629,19 @@ static const vector dat_object_definitions({ // Standard (triangular) cross-floor warp object. Params: // param4 = destination floor - // param6 = color (0 = blue, 1 = red); if this is 0 in Challenge mode, - // the warp is destroyed immediately + // param6 = color (0 = blue, 1 = red); if this is 0 in Challenge mode, the warp is destroyed immediately {0x0002, F_V0_V4, 0x00007FF3C07C78FF, "TObjAreaWarpForest"}, // Standard (triangular) intra-floor warp object. Params: - // param1-3 = destination coordinates (x, y, z); players are supposed - // to be offset from this location in different directions depending - // on their client ID, but there is a bug that causes all players to - // use the same offsets: x + 10 and z + 10 + // param1-3 = destination coordinates (x, y, z); players are supposed to be offset from this location in + // different directions depending on their client ID, but there is a bug that causes all players to use the + // same offsets: x + 10 and z + 10 // param4 = destination angle (about y axis) {0x0003, F_V0_V4, 0x00007FFC3FFF78FF, "TObjMapWarpForest"}, // Light collision. Params: - // param1 = TODO (in range 0-10000; if above 10000, (param1 - 10000) is - // used and a flag is set) - // param2 = TODO (in range 0-10000; if above 10000, (param2 - 10000) is - // used and a flag is set) + // param1 = TODO (in range 0-10000; if above 10000, (param1 - 10000) is used and a flag is set) + // param2 = TODO (in range 0-10000; if above 10000, (param2 - 10000) is used and a flag is set) // param3 = TODO // param4 = TODO // param5 = TODO @@ -662,12 +649,11 @@ static const vector dat_object_definitions({ {0x0004, F_V0_V4, 0x00006FFC3FFF87FF, "TObjLight"}, {0x0004, F_EP3, 0x0000000000008003, "TObjLight"}, - // Arbitrary item. The parameters specify the item data; see - // ItemCreator::base_item_for_specialized_box for how the encoding works. + // Arbitrary item. The parameters specify the item data; see ItemCreator::base_item_for_specialized_box for how the + // encoding works. {0x0005, F_V0_V2, 0x000000000000073F, "TItem"}, - // Environmental sound. This object is not constructed in offline multi - // mode. Params: + // Environmental sound. This object is not constructed in offline multi mode. Params: // param3 = audibility radius (if <= 0 uses default of 200) // param4 = sound ID: // Pioneer 2 / Lab (volume param is ignored on this floor): @@ -787,23 +773,19 @@ static const vector dat_object_definitions({ // Fog collision object. Params: // param1 = radius - // param4 = fog entry number; if lower than the existing fog number, - // does nothing (if param4 is >= 0x1000, the game subtracts 0x1000 - // from it, but only after comparing it to the current fog number; - // this can be used to override a later fog with an earlier fog) + // param4 = fog entry number; if lower than the existing fog number, does nothing (if param4 is >= 0x1000, the + // game subtracts 0x1000 from it, but only after comparing it to the current fog number; this can be used to + // override a later fog with an earlier fog) // param5 = transition type (0 = fade in, 1 = instantly switch) {0x0007, F_V0_V4, 0x00006FFFFFFF7FFF, "TObjFogCollision"}, {0x0007, F_EP3, 0x0000000000000001, "TObjFogCollision"}, - // Event collision object. This object triggers a wave event (W-XXX) when - // any local player (in split-screen play, there may be multiple) steps - // within its radius. The object is inactive for 3 frames after it is - // constructed, and will not detect any player during that time. - // Curiously, the frame counter does not appear to be bounded, so if the - // player waits approximately 828 days, the counter will overflow to a - // positive number and the object won't be able to trigger for another - // 828 days until it gets to zero again. It is unlikely this has ever - // happened for any player. Params: + // Event collision object. This object triggers a wave event (W-XXX) when any local player (in split-screen play, + // there may be multiple) steps within its radius. The object is inactive for 3 frames after it is constructed, and + // will not detect any player during that time. Curiously, the frame counter does not appear to be bounded, so if + // the player waits approximately 828 days, the counter will overflow to a positive number and the object won't be + // able to trigger for another 828 days until it gets to zero again. It is unlikely this has ever happened for any + // player. Params: // param1 = radius // param4 = event ID {0x0008, F_V0_V4, 0x00007FFFFFFF7FFF, "TObjEvtCollision"}, @@ -821,11 +803,9 @@ static const vector dat_object_definitions({ // param2 = explosion radius delta (actual radius is param2 / 2 + 60) // param3 = trap group number: // negative = trap triggers and explodes alone - // 0 = trap follows player who triggered it (online only; when - // offline, these act as if the group number were negative, and - // param6 is overwritten with 30 (1 second)) - // positive = trap is part of a group that all trigger and explode - // simultaneously + // 0 = trap follows player who triggered it (online only; when offline, these act as if the group number were + // negative, and param6 is overwritten with 30 (1 second)) + // positive = trap is part of a group that all trigger and explode simultaneously // param4 = trap power (clamped below to 0), scaled by difficulty: // Normal: power = param4 * 1 // Hard: power = param4 * 3 @@ -834,14 +814,12 @@ static const vector dat_object_definitions({ // param5 = damage type (clamped to [0, 5]) // 00 = direct damage (damage = power / 5) // 01 = fire (damage = power * (100 - EFR) / 500) - // 02 = cold (damage = power * (100 - EIC) / 500; chance of freezing = - // ((((power - 250) / 40) + 5) / 40) clamped to [0, 0.4], or to [0.2, - // 0.4] on Ultimate) - // 03 = electric (damage = power * (100 - EIC) / 500; chance of shock = - // 1/15, or 1/40 on Ultimate) + // 02 = cold (damage = power * (100 - EIC) / 500; chance of freezing = ((((power - 250) / 40) + 5) / 40) + // clamped to [0, 0.4], or to [0.2, 0.4] on Ultimate) + // 03 = electric (damage = power * (100 - EIC) / 500; chance of shock = 1/15, or 1/40 on Ultimate) // 04 = light (damage = power * (100 - ELT) / 500) - // 05 = dark (instantly kills with chance (power - EDK) / 100; if used - // in a boss arena and in non-Ultimate mode, cannot kill) + // 05 = dark (instantly kills with chance (power - EDK) / 100; if used in a boss arena and in non-Ultimate + // mode, cannot kill) // param6 = number of frames between trigger and explosion {0x000A, F_V0_V4, 0x00005FFC3FFB07FE, "TOMineIcon01"}, @@ -866,8 +844,8 @@ static const vector dat_object_definitions({ // param5 = trap type (clamped to [6, 8]) // 06 = heal HP (amount = power) // 07 = clear negative status effects - // 08 = does nothing? (TODO: calls player->vtable[0x40], but that - // function does nothing on v3. Did this do something in v1 or v2?) + // 08 = does nothing? (TODO: calls player->vtable[0x40], but that function does nothing on v3. Did this do + // something in v1 or v2?) // param6 = number of frames between trigger and explosion {0x000C, F_V0_V4, 0x00005FFC3FFB07FE, "TOMineIcon03"}, @@ -885,32 +863,28 @@ static const vector dat_object_definitions({ // param2 = next room ID // param3 = previous room ID // param5 = angle - // param6 = TODO (debug info calls this "BLOCK ID"; seems it only - // matters whether this is 0x10000 or not) + // param6 = TODO (debug info calls this "BLOCK ID"; seems it only matters whether this is 0x10000 or not) {0x000E, F_V0_V4, 0x00005FFFFFF83FFE, "TObjRoomId"}, // Sensor of some kind (TODO). Params: // param1 = activation radius delta (actual radius = param1 + 50) // param4 = switch flag number - // param5 = update mode switch (TODO; param5 < 0 sets update_mode = - // PERMANENTLY_ON, otherwise TEMPORARY; see TOSensor_vF) + // param5 = update mode switch (TODO; param5 < 0 sets update_mode = PERMANENTLY_ON, otherwise TEMPORARY; see + // TOSensor_vF) {0x000F, F_V0_V4, 0x00004000000000F6, "TOSensorGeneral01"}, - // Lens flare effect. This object is not constructed in offline multi - // mode. Params: + // Lens flare effect. This object is not constructed in offline multi mode. Params: // param1 = visibility radius (if negative, visible everywhere) {0x0011, F_V0_V4, 0x000040000000411E, "TEF_LensFlare"}, - // Quest script trigger. Starts a quest thread at a specific label when - // the local player goes near the object. Params: + // Quest script trigger. Starts a quest thread at a specific label when the local player is nearby. Params: // param1 = radius // param4 = label number to call when local player is within radius {0x0012, F_V0_V4, 0x00006FFFFFFC7FFF, "TObjQuestCol"}, {0x0012, F_EP3, 0x0000000000000001, "TObjQuestCol"}, - // Healing ring. Removes all negative status conditions and adds 9 HP and - // 9 TP per frame until max HP/TP are both reached or the player leaves - // the radius. The radius is a fixed size. + // Healing ring. Removes all negative status conditions and adds 9 HP and 9 TP per frame until max HP/TP are both + // reached or the player leaves the radius. The radius is a fixed size. {0x0013, F_V0_V4, 0x00004FFC3FF807FE, "TOHealGeneral"}, // Invisible map collision. Params: @@ -919,8 +893,7 @@ static const vector dat_object_definitions({ // 00 = custom (see param5) // 01 = blocks enemies only (as if param5 = 0x00008000) // 02 = blocks enemies and players (as if param5 = 0x00008900) - // 03 = blocks enemies and players, but enemies can see targets - // through the collision (as if param5 = 0x00000800) + // 03 = blocks enemies and players, but enemies can see targets through it (as if param5 = 0x00000800) // 04 = blocks players only (as if param5 = 0x00002000) // 05 = undefined behavior due to missing bounds check // anything else = same as 01 @@ -928,9 +901,8 @@ static const vector dat_object_definitions({ {0x0014, F_V0_V4, 0x0000600C3F87073F, "TObjMapCsn"}, {0x0014, F_EP3, 0x0000000000000001, "TObjMapCsn"}, - // Like TObjQuestCol, but requires the player to press a controller - // button to trigger the call. Parameters are the same as for - // TObjQuestCol. + // Like TObjQuestCol, but requires the player to press a controller button to trigger the call. Parameters are the + // same as for TObjQuestCol. {0x0015, F_V0_V4, 0x00006FFFFFFC7FFF, "TObjQuestColA"}, {0x0015, F_EP3, 0x0000000000000001, "TObjQuestColA"}, @@ -946,17 +918,14 @@ static const vector dat_object_definitions({ {0x0017, F_EP3, 0x0000000000008000, "TObjRaderCol"}, // Fog collision. Same params as 0x0007 (TObjFogCollision), but also: - // param3 = if >= 1, fog is on when switch flag is on; otherwise, fog - // is on when switch flag is off + // param3 = if >= 1, fog is on when switch flag is on; otherwise, fog is on when switch flag is off // param6 = switch flag number {0x0018, F_V0_V4, 0x00004FFFFFF87FFE, "TObjFogCollisionSwitch"}, - // Boss teleporter. The destination cannot be changed; it always - // teleports the player to the boss arena for the current area. In - // Challenge mode, the game uses the current area number to determine the - // destination floor, but in other modes, it uses the current episode - // number and floor number (not area number). Assuming areas haven't been - // reassigned from the defaults in non-Challenge mode, the mapping is: + // Boss teleporter. The destination cannot be changed; it always teleports the player to the boss arena for the + // current area. In Challenge mode, the game uses the current area number to determine the destination floor, but + // in other modes, it uses the current episode number and floor number (not area number). Assuming areas haven't + // been reassigned from the defaults in non-Challenge mode, the mapping is: // Challenge (indexed by area number, not floor number): // Episode 1: // Pioneer 2, boss arenas, lobby, battle areas => Pioneer 2 @@ -974,38 +943,30 @@ static const vector dat_object_definitions({ // Pioneer 2, boss arena => Pioneer 2 // Crater, Desert, test map => Saint-Milion arena // Params: - // param5 = switch flag number required to activate warp (>= 0x100 = no - // switch flag required; ignored if on Pioneer 2) + // param5 = switch flag number required to activate (>= 0x100 = no switch flag required; ignored if on Pioneer 2) // In offline mode, this object constructs TObjWarpBossMulti instead. {0x0019, F_V0_V4, 0x00006FFC3FFC04A5, "TObjWarpBoss"}, - // Sign board. This shows the loaded image from a quest (via load_pvr). On - // the final version of PCv2, this object doesn't render at all; my guess - // is that Sega hardcoded the PVR filenames for the various events in the - // executable, then after those events ended, they just deleted the - // load_pvr code entirely, leaving this object nonfunctional. - // Params: + // Sign board. This shows the loaded image from a quest (via load_pvr). On the final version of PCv2, this object + // doesn't render at all; my guess is that Sega hardcoded the PVR filenames for the various events in the + // executable, then after those events ended, they just deleted the load_pvr code entirely, leaving this object + // nonfunctional. Params: // param1-3 = scale factors (x, y, z) {0x001A, F_V1_V4, 0x0000600000040001, "TObjSinBoard"}, {0x001A, F_EP3, 0x0000000000000001, "TObjSinBoard"}, - // Quest floor warp. This appears similar to TObjAreaWarpForest except - // that the object is not destroyed immediately if it's blue and the game - // is Challenge mode. Params: - // param1 = player set ID (TODO: what exactly does this do? Looks like it - // does nothing unless it's >= 2; see TObjPlayerSet) + // Quest floor warp. This appears similar to TObjAreaWarpForest except that the object is not destroyed immediately + // if it's blue and the game is Challenge mode. Params: + // param1 = player set ID (TODO: what does this do? Seems it does nothing unless it's >= 2; see TObjPlayerSet) // param4 = destination floor // param6 = color (0 = blue, 1 = red) {0x001B, F_V1_V4, 0x00005000000078FE, "TObjAreaWarpQuest"}, - // Ending movie warp (used in final boss arenas after the boss is - // defeated). Params: + // Ending movie warp (used in final boss arenas after the boss is defeated). Params: // param6 = color (0 = blue, 1 = red) {0x001C, F_V1_V4, 0x0000500080004000, "TObjAreaWarpEnding"}, - // Star light effect. - // This object renders from -100 to 740 over x and -100 to 580 over y. - // Params: + // Star light effect. This object renders from -100 to 740 over x and -100 to 580 over y. Params: // param1 = TODO // param2 = TODO // param3 = TODO (1 byte only) @@ -1014,8 +975,7 @@ static const vector dat_object_definitions({ // param6 = TODO (1 byte only) {0x001D, F_V2_V4, 0x0000400000000002, "TEffStarLight2D_Base"}, - // VR Temple Beta / Barba Ray lens flare effect. - // This object renders from -10 to 650 over x and -10 to 490 over y. + // VR Temple Beta / Barba Ray lens flare effect. This object renders from -10 to 650 over x and -10 to 490 over y. {0x001E, F_V2_V4, 0x000041F1001A0006, "__LENS_FLARE__"}, // Hides the area map when the player is near this object. Params: @@ -1034,31 +994,24 @@ static const vector dat_object_definitions({ // 5 = mag // 6 = tool // 7 = meseta - // param6 = item amount required minus 1 (0 = 1 item, 1 = 2 items, etc.); - // for tools and meseta, each dropped item counts for its stack size + // param6 = item amount required minus 1 (0 = 1 item, 1 = 2 items, etc.); for tools and meseta, each dropped item + // counts for its stack size {0x0020, F_V2_V4, 0x00006FFC3FFF07FF, "TOSwitchItem"}, - // Symbol chat collision object. This object triggers symbol chats when - // the players are nearby and certain switch flags are NOT set. If a - // player is within the radius, the object checks the switch flags in - // reverse order, and triggers the symbol chat for the latest one that is - // NOT set. So, the logic is: + // Symbol chat collision object. This object triggers symbol chats when the players are nearby and certain switch + // flags are NOT set. If a player is within the radius, the object checks the switch flags in reverse order, and + // triggers the symbol chat for the latest one that is NOT set. So, the logic is: // - If all 3 switch flags are not set, the symbol chat in spec1 is used - // - If the switch flag in spec1 is set and those in spec2 and spec3 are - // not set, the symbol chat in spec2 is used - // - If the switch flag in spec2 is set and the flag in spec3 is not set, - // the symbol chat in spec3 is used regardless of whether the switch - // flags in spec1 is set - // - If the switch flags in spec3 is set, no symbol chat appears at all - // regardless of the values of the other two switch flags - // Each spec is a 32-bit integer consisting of two 16-bit fields. The - // high 16 bits are a switch flag number (0-255), and the low 16 bits are - // an entry index from symbolchatcolli.prs. The entry index is ignored if - // the corresponding data label from the F8A6 quest opcode is not null - // (and the data from the label is used instead). Quest scripts don't - // have a good way to pass null for regsA[7-9], so the logic that looks - // up entries in symbolchatcolli.prs can be ignored in quests. - // Default symbol chat numbers (from qedit.info): + // - If the switch flag in spec1 is set and those in spec2 and spec3 are not set, the symbol chat in spec2 is used + // - If the switch flag in spec2 is set and the flag in spec3 is not set, the symbol chat in spec3 is used + // regardless of whether the switch flags in spec1 is set + // - If the switch flags in spec3 is set, no symbol chat appears at all regardless of the values of the other two + // switch flags + // Each spec is a 32-bit integer consisting of two 16-bit fields. The high 16 bits are a switch flag number + // (0-255), and the low 16 bits are an entry index from symbolchatcolli.prs. The entry index is ignored if the + // corresponding data label from the F8A6 quest opcode is not null (and the data from the label is used instead). + // Quest scripts don't have a good way to pass null for regsA[7-9], so the logic that looks up entries in + // symbolchatcolli.prs can be ignored in quests. Default symbol chat numbers (from qedit.info): // 00 = Drop Meseta // 01 = Meseta has been dropped // 02 = Drop 1 weapon @@ -1088,37 +1041,31 @@ static const vector dat_object_definitions({ // param4 = spec1 // param5 = spec2 // param6 = spec3 - // This object can also be created by the quest opcode F8A6; see the - // description of that opcode in QuestScript.cc for more information. + // This object can also be created by the quest opcode F8A6; see the description of that opcode in QuestScript.cc + // for more information. {0x0021, F_V2_V4, 0x00006FFC3FFF07FF, "TOSymbolchatColli"}, // Invisible collision switch. Params: // param1 = radius delta (actual radius is param1 + 10) // param4 = switch flag number - // param5 = sticky flag (if negative, switch flag is unset when player - // leaves; if zero or positive, switch flag remains on) + // param5 = sticky flag (if negative, switch flag is unset when player leaves; if zero or positive, switch flag + // remains on) {0x0022, F_V2_V4, 0x00004FFC3FFB07FE, "TOKeyCol"}, // Attackable collision. Params: - // param1 = enable switch flag (the object is only attackable if this - // switch flag is enabled); any value > 0xFF disables this behavior - // so the object is always attackable - // param2 = if negative, no target reticle appears; if zero or - // positive, a reticle appears - // param3 = switch flag number to set when required number of hits is - // taken (ignored if param6 is nonzero) - // param4 = number of hits required to activate, minus 1 (so e.g. a - // value of 4 here means 5 hits needed) - // param5 = object number (if outside the range [100, 999], uses the - // free play script when looking up param6 instead of the quest) - // param6 = quest label to call when required number of hits is taken - // (if zero, switch flag in param3 is set instead) + // param1 = enable switch flag (the object is only attackable if this switch flag is enabled); any value > 0xFF + // disables this behavior so the object is always attackable + // param2 = if negative, no target reticle appears; if zero or positive, a reticle appears + // param3 = switch flag number to set when required number of hits is taken (ignored if param6 is nonzero) + // param4 = number of hits required to activate, minus 1 (so e.g. a value of 4 here means 5 hits needed) + // param5 = object number (if outside the range [100, 999], uses the free play script when looking up param6 + // instead of the quest) + // param6 = quest label to call when all required hits are taken (if zero, switch flag in param3 is set instead) {0x0023, F_V2_V4, 0x00004FFC3FFB07FE, "TOAttackableCol"}, // Damage effect. Params: - // angle.x = effect type (in range [0x00, 0x14]; the following were - // tested in Forest 1 and may have different effects in different - // areas): + // angle.x = effect type (in range [0x00, 0x14]; the following were tested in Forest 1 and may have different + // effects in different areas): // 00 = fiery explosion with vertical camera shake // 01 = vertical camera shake only // 02 = bluish energy ball @@ -1147,40 +1094,31 @@ static const vector dat_object_definitions({ // Very Hard: param2 * 6 // Ultimate: param2 * 8 // param3 = effect visual size - // param4 = enable switch flag number (effect is off unless this flag - // is set) - // param5 = disable switch flag number (effect is off if this flag is - // set, even if the enable switch flag is also set), or >= 0x100 if - // this functionality isn't needed + // param4 = enable switch flag number (effect is off unless this flag is set) + // param5 = disable switch flag number (effect is off if this flag is set, even if the enable switch flag is also + // set), or >= 0x100 if this functionality isn't needed // param6 = persistence flag (if nonzero, effect stays on once enabled) {0x0024, F_V2_V4, 0x0000600FFF9F07FF, "TOSwitchAttack"}, - // Switch flag timer. This object watches for a switch flag to be - // activated, then once it is, waits for a specified time, then disables - // that switch flag or activates up to three other switch flags. Note that - // this object just provides the timer functionality; the trigger switch - // flag must be activated by some other object. Params: + // Switch flag timer. This object watches for a switch flag to be activated, then once it is, waits for a specified + // time, then disables that switch flag or activates up to three other switch flags. Note that this object just + // provides the timer functionality; the trigger switch flag must be activated by some other object. Params: // angle.x = trigger mode: // 0 = disable watched switch flag when timer expires - // any positive number = enable up to 3 other switch flags when timer - // expires and don't disable watched switch flag - // angle.y = if this is 1, play tick sound effect every second after - // activation (if any other value, no tick sound is played) + // any positive number = enable up to 3 other flags when timer expires and don't disable the watched flag + // angle.y = if this is 1, play tick sound effect every second after activation (if any other value, no tick + // sound is played) // angle.z = timer duration in frames - // param4 = switch flag to watch for activation in low 16 bits, switch - // flag 1 to activate when timer expires (if angle.x != 0) in high 16 - // bits (>= 0x100 if not needed) - // param5 = switch flag 2 to activate when timer expires (if - // angle.x != 0) in high 16 bits (>= 0x100 if not needed) - // param6 = switch flag 3 to activate when timer expires (if + // param4 = switch flag to watch for activation in low 16 bits, switch flag 1 to activate when timer expires (if // angle.x != 0) in high 16 bits (>= 0x100 if not needed) + // param5 = switch flag 2 to activate when timer expires (if angle.x != 0) in high 16 bits (>= 0x100 if none) + // param6 = switch flag 3 to activate when timer expires (if angle.x != 0) in high 16 bits (>= 0x100 if none) {0x0025, F_V2_V4, 0x00006FFC3FFF07FF, "TOSwitchTimer"}, - // Chat sensor. This object watches for chat messages said by players - // within its radius, optionally filtering for specific words. When a - // message matches, it either activates a switch flag or calls a quest - // function. When created via the F801 quest opcode, param5 is ignored, - // and the string specified by the quest is always used. Params: + // Chat sensor. This object watches for chat messages said by players within its radius, optionally filtering for + // specific words. When a message matches, it either activates a switch flag or calls a quest function. When + // created via the F801 quest opcode, param5 is ignored, and the string specified by the quest is always used. + // Params: // angle.x = activation type (0 = quest function, 1 = switch flag) // angle.y = match mode: // 0 = match a specific string (defined by param5) @@ -1195,27 +1133,22 @@ static const vector dat_object_definitions({ // 3 = "NO" {0x0026, F_V2_V4, 0x00006FFC3FFF07FF, "TOChatSensor"}, - // Radar map icon. Shows an icon on the map that is optionally locked or - // unlocked, depending on the values of one or more sequential switch - // flags. The icon is considered unlocked if all of the specified switch - // flags are set. There can be at most 12 switch flags used with this - // object and the switch flag numbers cannot wrap around from 0xFF to 0. - // Params: + // Radar map icon. Shows an icon on the map that is optionally locked or unlocked, depending on the values of one + // or more sequential switch flags. The icon is considered unlocked if all of the specified switch flags are set. + // There can be at most 12 switch flags used with this object and the switch flag numbers cannot wrap around from + // 0xFF to 0. Params: // param1 = scale (1.0 = normal size) // param4 = check switch flags for color: - // positive value = ignore param6; color is red (FFFF0000) if any of - // the switch flags are off, or green (FF00FF00) if all are on - // zero or negative = ignore param5; always render in the color - // specified by param6 - // param5 = switch flag spec; upper 16 bits are number of switch flags, - // lower 16 bits are first switch flag number + // positive value = ignore param6; color is red (FFFF0000) if any of the switch flags are off, or green + // (FF00FF00) if all are on + // zero or negative = ignore param5; always render in the color specified by param6 + // param5 = switch flag spec; high 16 bits are number of switch flags, low 16 bits are first switch flag number // param6 = color as ARGB8888 {0x0027, F_V3_V4, 0x00004FFFFFFC0000, "TObjRaderIcon"}, - // Environmental sound. This object is not constructed in offline multi - // mode. This is essentially identical to TObjEnvSound, except the sound - // fades in and out instead of abruptly starting or stopping when - // entering or leaving its radius. Params: + // Environmental sound. This object is not constructed in offline multi mode. This is essentially identical to + // TObjEnvSound, except the sound fades in and out instead of abruptly starting or stopping when entering or + // leaving its radius. Params: // param2 = volume fade speed (units per frame) // param3 = audibility radius (same as for TObjEnvSound) // param4 = sound ID (same as for TObjEnvSound) @@ -1223,16 +1156,14 @@ static const vector dat_object_definitions({ {0x0028, F_V3_V4, 0x00006FFCBFFF27F7, "TObjEnvSoundEx"}, {0x0028, F_EP3, 0x0000000000000001, "TObjEnvSoundEx"}, - // Environmental sound. This object is not constructed in offline multi - // mode. This is essentially identical to TObjEnvSound, except there is - // no radius: the sound is audible everywhere. Params: + // Environmental sound. This object is not constructed in offline multi mode. This is essentially identical to + // TObjEnvSound, except there is no radius: the sound is audible everywhere. Params: // param4 = sound ID (same as for TObjEnvSound) // param5 = volume (same as for TObjEnvSound) {0x0029, F_V3_V4, 0x00006FFCBFFF27F7, "TObjEnvSoundGlobal"}, {0x0029, F_EP3, 0x0000000000000001, "TObjEnvSoundGlobal"}, - // Counter sequence activator. Used for Hunter's Guild, shops, bank, etc. - // Params: + // Counter sequence activator. Used for Hunter's Guild, shops, bank, etc. Params: // param4 = shop sequence number: // Episodes 1, 2, and 4: // 00 = weapon shop @@ -1267,8 +1198,7 @@ static const vector dat_object_definitions({ {0x0041, F_V0_V4, 0x0000600000040001, "TObjLuker"}, {0x0041, F_EP3, 0x0000000000000001, "TObjLuker"}, - // BGM collision. Changes the background music when the player enters the - // object's radius. Params: + // BGM collision. Changes the background music when the player enters the object's radius. Params: // param1 = radius // param4 = which music to play: // 00 = SHOP.adx @@ -1281,31 +1211,28 @@ static const vector dat_object_definitions({ {0x0042, F_V0_V4, 0x0000600000040001, "TObjBgmCol"}, {0x0042, F_EP3, 0x0000000000000001, "TObjBgmCol"}, - // Main warp to other floors from Pioneer 2. - // Certain floors are available by default, determined by checking the - // game's mode and quest flags. A different set of flags is checked on BB - // than on other versions, presumably since government quests are used to - // unlock areas instead of offline story progression. On later versions - // of BB, all floors are available by default; this table reflects the - // behavior before that change. - // Required flag for mode: Online/multi Offline BB flag + // Main warp to other floors from Pioneer 2. Certain floors are available by default, determined by checking the + // game's mode and quest flags. A different set of flags is checked on BB than on other versions, presumably since + // government quests are used to unlock areas instead of offline story progression. On later versions of BB, all + // floors are available by default; this table reflects the behavior before that change. + // Required flag for mode: Online/multi Offline BB (all modes) // Episode 1: - // Forest 1: Always open Always open Always open - // Cave 1: 0x17 0x18 0x1F9 - // Mine 1: 0x20 0x21 0x201 - // Ruins 1: 0x30 0x2A 0x207 + // Forest 1: Always open Always open Always open + // Cave 1: 0x17 0x18 0x1F9 + // Mine 1: 0x20 0x21 0x201 + // Ruins 1: 0x30 0x2A 0x207 // Episode 2: - // VR Temple Alpha: Always open Always open Always open - // VR Spaceship Alpha: 0x4C 0x4D 0x21B - // CCA: 0x4F 0x50 0x225 - // Seabed Upper: 0x52 0x53 0x22F + // VR Temple Alpha: Always open Always open Always open + // VR Spaceship Alpha: 0x4C 0x4D 0x21B + // CCA: 0x4F 0x50 0x225 + // Seabed Upper: 0x52 0x53 0x22F // Episode 4: - // Crater East Always open - // Crater West 0x2BD - // Crater South 0x2BE - // Crater North 0x2BF - // Crater Interior 0x2C0 - // Subterranean Desert 1 0x2C1 + // Crater East Always open + // Crater West 0x2BD + // Crater South 0x2BE + // Crater North 0x2BF + // Crater Interior 0x2C0 + // Subterranean Desert 1 0x2C1 // Params: // param5 = main warp type: // 00 = Episode 1 / Episode 4 @@ -1313,16 +1240,13 @@ static const vector dat_object_definitions({ // 02 = Ep2 CCA (VR Temple and Spaceship not available) {0x0043, F_V0_V4, 0x0000600000040001, "TObjCityMainWarp"}, - // Lobby teleporter. When used, this object immediately ends the current - // game and sends the player back to the lobby. If constructed offline, - // this object will do nothing and not render. - // This object takes no parameters. + // Lobby teleporter. When used, this object immediately ends the current game and sends the player back to the + // lobby. If constructed offline, this object will do nothing and not render. This object takes no parameters. {0x0044, F_V0_V4, 0x0000600000040001, "TObjCityAreaWarp"}, {0x0044, F_EP3, 0x0000000000000001, "TObjCityAreaWarp"}, - // Warp to another location on the same map. Used for the Principal's - // office warp. This warp is visible in all game modes, but cannot be - // used in Battle or Challenge mode. Params: + // Warp to another location on the same map. Used for the Principal's office warp. This warp is visible in all game + // modes, but cannot be used in Battle or Challenge mode. Params: // param1-3 = destination (same as for TObjMapWarpForest) // param4 = destination angle (same as for TObjMapWarpForest) // param5 = shape (0 = hexagonal, nonzero = "round" (12-sided)) @@ -1341,9 +1265,8 @@ static const vector dat_object_definitions({ // Elevator visible in Pioneer 2. There appear to be no parameters. {0x004A, F_V0_V4, 0x0000600000000001, "__ELEVATOR__"}, - // Holiday event decorations. There appear to be no parameters, except - // TObjCity_Season_SonicAdv2, which takes param4 = model index (clamped - // to [0, 3]). + // Holiday event decorations. There appear to be no parameters, except TObjCity_Season_SonicAdv2, which takes + // param4 = model index (clamped to [0, 3]). {0x004B, F_V0_V4, 0x0000600000040001, "TObjCity_Season_EasterEgg"}, {0x004C, F_V0_V4, 0x0000600000040001, "TObjCity_Season_ValentineHeart"}, {0x004D, F_V0_V4, 0x0000600000040001, "TObjCity_Season_XmasTree"}, @@ -1357,24 +1280,18 @@ static const vector dat_object_definitions({ // param1 = area width // param2 = base height // param3 = area depth - // param4 = launch frequency (when a firework is launched, the game - // generates a random number r in range [0, 0x7FFF] and waits - // ((param4 + 60) * (r / 0x8000) * 3.0)) frames before launching the - // next firework) + // param4 = launch frequency (when a firework is launched, the game generates a random number r in range [0, + // 0x7FFF] and waits ((param4 + 60) * (r / 0x8000) * 3.0)) frames before launching the next firework) {0x0053, F_V0_V4, 0x0000600400040001, "TObjCity_Season_FireWorkCtrl"}, - // Door that blocks the lobby teleporter in offline mode. There appear to - // be no parameters. + // Door that blocks the lobby teleporter in offline mode. There appear to be no parameters. {0x0054, F_V0_V4, 0x0000600000000001, "TObjCityDoor_Lobby"}, - // Version of the main warp for Challenge mode. This object looks like the - // main Ragol warp on Pioneer 2, but behaves similarly to boss teleporters: - // it shows the player a Yes/No confirmation menu and sends 6x6A to - // synchronize state. There is a global named last_set_mainwarp_value which - // is set to param4 when this object is constructed, but may be changed by - // a set_mainwarp quest opcode after that. If that happens, this object - // replaces its dest_floor with the floor specified in the last - // set_mainwarp quest opcode. Params: + // Version of the main warp for Challenge mode. This object looks like the main Ragol warp on Pioneer 2, but + // behaves similarly to boss teleporters: it shows the player a Yes/No confirmation menu and sends 6x6A to + // synchronize state. There is a global named last_set_mainwarp_value which is set to param4 when this object is + // constructed, but may be changed by a set_mainwarp quest opcode after that. If that happens, this object replaces + // its dest_floor with the floor specified in the last set_mainwarp quest opcode. Params: // param4 = destination floor // param5 = switch flag number {0x0055, F_V2_V4, 0x0000600000040001, "TObjCityMainWarpChallenge"}, @@ -1382,40 +1299,33 @@ static const vector dat_object_definitions({ // Episode 2 Lab door. Params: // param4 = switch flag number and activation mode: // negative value = always unlocked - // value in [0x00, 0x100] = unlocked by a switch flag (the bounds - // check appears to be a bug; the range should be [0x00, 0xFF] but - // the game has an off-by-one error) + // value in [0x00, 0x100] = unlocked by a switch flag (the bounds check appears to be a bug; the range should + // be [0x00, 0xFF] but the game has an off-by-one error) // value > 0x100 = always locked // param5 = model (green or red; clamped to [0, 1]) - // param6 = if negative, all switches must be active simultaneously to - // unlock the door; if zero or positive, they may be activated - // sequentially instead (in offline solo mode, this is ignored and - // the sequential behavior is always used); this is somewhat obviated - // for this door type since it can have only one switch flag, but - // other door types may have multiple, for which this is relevant + // param6 = if negative, all switches must be active simultaneously to unlock the door; if zero or positive, they + // may be activated sequentially instead (in offline solo mode, this is ignored and the sequential behavior is + // always used); this is somewhat obviated for this door type since it can have only one switch flag, but other + // door types may have multiple, for which this is relevant {0x0056, F_V3_V4, 0x0000400000040000, "TODoorLabo"}, - // Enables the Trade Window when the player is near this object. Both - // players must be near a TObjTradeCollision object (not necessarily the - // same one) to be able to use the Trade Window with each other. Params: + // Enables the Trade Window when the player is near this object. Both players must be near a TObjTradeCollision + // object (not necessarily the same one) to be able to use the Trade Window with each other. Params: // param1 = radius {0x0057, F_V3_V4, 0x0000600000040001, "TObjTradeCollision"}, {0x0057, F_EP3, 0x0000000000000001, "TObjTradeCollision"}, - // This object appears to be unused in both Ep3 NTE and the final release. - // It may have been an early version of Deck Edit or Entry Counter - // sequence, perhaps responsible for setting the players' statuses when - // they're near either of those counters. Params: + // This object appears to be unused in both Ep3 NTE and the final release. It may have been an early version of + // Deck Edit or Entry Counter sequence, perhaps responsible for setting the players' statuses when they're near + // either of those counters. Params: // param1 = radius {0x0058, F_EP3, 0x0000000000000001, "TObjDeckCollision"}, // Forest door. Params: // param1-3 = x, y, z coordinates for unlock "cutscene" (see param6) - // param4 = switch flag number (low byte) and number to appear on door - // (second-lowest byte, modulo 10) - // param6 = if set to 1, enables unlock "cutscene" - when the door is - // unlocked, the camera will snap to the coordinates in param1-3, - // pointing toward the door, for 2 seconds + // param4 = switch flag number (low byte) and number to appear on door (second-lowest byte, modulo 10) + // param6 = if set to 1, enables unlock "cutscene" - when the door is unlocked, the camera will snap to the + // coordinates in param1-3, pointing toward the door, for 2 seconds {0x0080, F_V0_V4, 0x0000400000000006, "TObjDoor"}, // Forest switch. Params: @@ -1454,55 +1364,47 @@ static const vector dat_object_definitions({ {0x0087, F_V0_V4, 0x0000400000000006, "TMotorcycle"}, // Item box. Params: - // param1 = if positive, box is specialized to drop a specific item or - // type of item; if zero or negative, box drops any common item or - // none at all (and param3-6 are all ignored) - // param3 = if zero, then only data1[0-1] are used and the rest of the - // ItemData is cleared, then bonuses, grinds, etc. are applied to the - // item; if nonzero, the item is not randomized at all and drops - // exactly as specified in param4-6 + // param1 = if positive, box is specialized to drop a specific item or type of item; if zero or negative, box + // drops any common item or none at all (and param3-6 are all ignored) + // param3 = if zero, then only data1[0-1] are used and the rest of the ItemData is cleared, then bonuses, grinds, + // etc. are applied to the item; if nonzero, the item is not randomized at all and drops exactly as specified + // in param4-6 // param4-6 = item definition (see below) - // Not all fields in ItemData can be specified in the item definition here. - // The field order here does not match the field order in ItemData! The - // item definition is encoded here as follows: - // -param4- -param5- -param6- - // Weapon: 00wwZZSS GG--PPQQ PPQQPPQQ - // Armor: 0100ZZTT 00VV---- -------- - // Shield: 0101ZZTT 00VV---- -------- - // Unit: 0102ZZ00 00VV---- -------- - // Mag: 02zz---- -------- -------- - // Tool: 03zzZZ-- -------- -------- - // Tech disk: 0302&&%% -------- -------- - // Meseta: 040000-- $$$$---- -------- + // Not all fields in ItemData can be specified in the item definition here. The field order here does not match the + // field order in ItemData! The item definition is encoded here as follows: + // -param4- -param5- -param6- + // Weapon: 00wwZZSS GG--PPQQ PPQQPPQQ + // Armor: 0100ZZTT 00VV---- -------- + // Shield: 0101ZZTT 00VV---- -------- + // Unit: 0102ZZ00 00VV---- -------- + // Mag: 02zz---- -------- -------- + // Tool: 03zzZZ-- -------- -------- + // Tech disk: 0302&&%% -------- -------- + // Meseta: 040000-- $$$$---- -------- + // Fields in the above table: // - = ignored // G = weapon grind - // P = attribute type (for S-ranks, custom name; last pair is kill count - // for some weapons) - // Q = attribute amount (for S-ranks, custom name; last pair is kill - // count for some weapons) + // P = attribute type (for S-ranks, custom name; last pair is kill count for some weapons) + // Q = attribute amount (for S-ranks, custom name; last pair is kill count for some weapons) // S = weapon flags (80=untekked, 40=present) and special (low 6 bits) // T = slot count // U = tool flags (40=present; unused if item is stackable) // V = armor/shield/unit flags (40=present; low 4 bits are present color) - // w = weapon class - 1 (second byte of item code, offset by 1, so e.g. - // Mechgun is 07 here, not 08) + // w = weapon class - 1 (second byte of item code, offset by 1, so e.g. Mechgun is 07 here, not 08) // z = item class (second byte of item code) // Z = item subclass (third byte of item code) // & = technique level // % = technique number // $ = meseta amount, divided by 10 (so max possible amount is 655350) - // See base_item_for_specialized_box in ItemCreator.cc for newserv's - // implementation of decoding this format. - // In the non-specialized case (param1 <= 0), param3-6 are still sent via - // the 6xA2 command when the box is opened on v3 and later, and the - // server may choose to use those parameters for some purpose. The client - // implementation ignores them when param1 <= 0, and newserv does too. + // See base_item_for_specialized_box in ItemCreator.cc for newserv's implementation of decoding this format. + // In the non-specialized case (param1 <= 0), param3-6 are still sent via the 6xA2 command when the box is opened + // on v3 and later, and the server may choose to use those parameters for some purpose. The client implementation + // ignores them when param1 <= 0, and newserv does too. {0x0088, F_V0_V4, 0x00004FF0B00000FE, "TObjContainerBase2"}, {0x0088, F_EP3, 0x0000000000000002, "TObjContainerBase2"}, - // Elevated cylindrical tank. There appear to be no parameters; param1-3 - // are copied into the object instance as a Vector3F, but it appears that - // that vector is never used. + // Elevated cylindrical tank. There appear to be no parameters; param1-3 are copied into the object instance as a + // Vector3F, but it appears that that vector is never used. {0x0089, F_V0_V4, 0x0000400000000006, "TObjTank"}, // TODO: Describe this object. Params: @@ -1510,53 +1412,44 @@ static const vector dat_object_definitions({ {0x008A, F_V0_V2, 0x0000000000000006, "TObjBattery"}, // Forest console. Params: - // param4 = quest label to call when activated (inherited from - // TObjMesBase) + // param4 = quest label to call when activated (inherited from TObjMesBase) // param5 = model (clamped to [0, 1]) - // param6 = type (clamped to [0, 1]; 0 = "QUEST", 1 = "RICO") - // (inherited from TObjMesBase) + // param6 = type (clamped to [0, 1]; 0 = "QUEST", 1 = "RICO") (inherited from TObjMesBase) {0x008B, F_V0_V1, 0x0000000000000406, "TObjComputer"}, {0x008B, F_V2_V4, 0x00004FFC3FFB07FE, "TObjComputer"}, // Black sliding door. Params: - // param1 = total distance (divided evenly by the number of switch - // flags, from param4) + // param1 = total distance (divided evenly by the number of switch flags, from param4) // param2 = speed - // param4 = base switch flag (the actual switch flags used are param4, - // param4 + 1, param4 + 2, etc.) + // param4 = base switch flag (the actual switch flags used are param4, param4 + 1, param4 + 2, etc.) // param5 = number of switch flags (clamped to [1, 4]) // param6 = movement effect (0 = sparks + thud, 1 = grinding sound) {0x008C, F_V0_V1, 0x0000000000000006, "TObjContainerIdo"}, {0x008C, F_V2_V4, 0x000040000000000E, "TObjContainerIdo"}, - // Rico message pod. This object immediately destroys itself in Challenge - // mode or split-screen mode. Params: + // Rico message pod. This object immediately destroys itself in Challenge mode or split-screen mode. Params: // param4 = enable condition: // negative = enabled when player is within 70 units // range [0x00, 0xFF] = enabled by corresponding switch flag // 0x100 and above = never enabled - // param5 = message number ("character ID" in qedit; if this is outside - // the range [100, 999], the quest label in param6 is called in the - // free play script instead of the quest script) + // param5 = message number ("character ID" in qedit; if this is outside the range [100, 999], the quest label in + // param6 is called in the free play script instead of the quest script) // param6 = quest label to call when activated {0x008D, F_V0_V4, 0x00004000000027FE, "TOCapsuleAncient01"}, // Energy barrier. Params: - // param4 = switch flag number and activation mode (same as for - // TODoorLabo) + // param4 = switch flag number and activation mode (same as for TODoorLabo) {0x008E, F_V0_V4, 0x00004FF0000000F6, "TOBarrierEnergy01"}, - // Forest rising bridge. Once enabled (risen), this object cannot be - // disabled; that is, there is no way to make the bridge retract. When - // disabled, the bridge is 30 units below its initial position; when - // enabled, it rises to its initial position. Params: + // Forest rising bridge. Once enabled (risen), this object cannot be disabled; that is, there is no way to make the + // bridge retract. When disabled, the bridge is 30 units below its initial position; when enabled, it rises to its + // initial position. Params: // param2 = rise speed in units per frame // param4 = switch flag number {0x008F, F_V0_V4, 0x0000400000000006, "TObjHashi"}, - // Generic switch. Visually, this is the type usually used for objects - // other than doors, such as lights, poison rooms, and the Forest 2 - // bridge. Params: + // Generic switch. Visually, this is the type usually used for objects other than doors, such as lights, poison + // rooms, and the Forest 2 bridge. Params: // param1 = activation mode: // negative = temporary (TODO: test this) // zero or positive = permanent (normal) @@ -1567,8 +1460,7 @@ static const vector dat_object_definitions({ // param4 = event number {0x0091, F_V0_V4, 0x00004FF0300000FE, "TObjContainerEnemy"}, - // Large box (usually used for specialized drops). Same parameters as - // 0x0088 (TObjContainerBase2) + // Large box (usually used for specialized drops). Same parameters as 0x0088 (TObjContainerBase2) {0x0092, F_V0_V4, 0x00005E00B00078FE, "TObjContainerBase"}, // Large enemy box. Same parameters as 0x0091 (TObjContainerEnemy). @@ -1596,43 +1488,35 @@ static const vector dat_object_definitions({ {0x00C0, F_V0_V4, 0x00004FFC3FFB0038, "TOKeyCave01"}, // Caves multiplayer door. Params: - // param4 = base switch flag number (the actual switch flags used are - // param4, param4 + 1, param4 + 2, etc.; if this is negative, the - // door is always unlocked) - // param5 = 4 - number of switch flags (so if e.g. door should require - // only 3 switch flags, set param5 to 1) + // param4 = base switch flag number (the actual switch flags used are param4, param4 + 1, param4 + 2, etc.; if + // this is negative, the door is always unlocked) + // param5 = 4 - number of switch flags (so if e.g. door should require only 3 switch flags, set param5 to 1) // param6 = synchronization mode: - // negative = when all switch flags are enabled, door is permanently - // unlocked via 6x0B even if some switch flags are disabled later - // zero or positive = door only stays unlocked while all of the - // switch flags are active and locks again when any are disabled - // (no effect in single-player offline mode; the negative behavior - // is used instead) + // negative = when all switch flags are enabled, door is permanently unlocked via 6x0B even if some switch + // flags are disabled later + // zero or positive = door only stays unlocked while all of the switch flags are active and locks again when + // any are disabled (no effect in single-player offline mode; the negative behavior is used instead) {0x00C1, F_V0_V4, 0x0000400000000038, "TODoorCave01"}, // Caves standard door. Params: - // param4 = switch flag number (negative = always unlocked; >0x100 = - // always locked) + // param4 = switch flag number (negative = always unlocked; >0x100 = always locked) {0x00C2, F_V0_V4, 0x0000400000000038, "TODoorCave02"}, - // Caves ceiling piston trap. There are three types of this object, which - // can be chosen via param6. If param6 is not 0, 1, or 2, no object is - // created. + // Caves ceiling piston trap. There are three types of this object, which can be chosen via param6. If param6 is + // not 0, 1, or 2, no object is created. // Params for TOHangceilingCave01Normal (param6 = 0): - // param1 = 1/4 time between crushes, in frames (value is param1 + 29, so - // total time between crushes is (param1 + 29) * 4 frames) - // param2 = wait time in frames after construction until first crush - // (value is 1 - param2, so a more negative value means a longer wait - // time) - // param3 = base damage (value is param3 + 100; scaled by difficulty: - // Normal = 1x, Hard = 2x, Very Hard = 3x, Ultimate = 6x) + // param1 = 1/4 time between crushes, in frames (value is param1 + 29, so total time between crushes is (param1 + + // 29) * 4 frames) + // param2 = wait time in frames after construction until first crush (value is 1 - param2, so a more negative + // value means a longer wait time) + // param3 = base damage (value is param3 + 100; scaled by difficulty: Normal = 1x, Hard = 2x, Very Hard = 3x, + // Ultimate = 6x) // Params for TOHangceilingCave01Key (param6 = 1): // param1-3 = same as for TOHangceilingCave01Normal - // param4 = switch flag number (drops when switch flag is activated; - // when it has finished dropping, it disables the switch flag) + // param4 = switch flag number (drops when switch flag is activated; when it has finished dropping, it disables + // the switch flag) // Params for TOHangceilingCave01KeyQuick (param6 = 2): - // param1-4 = same as for TOHangceilingCave01Key, but unlike that - // object, does not disable the switch flag automatically + // param1-4 = same as for TOHangceilingCave01Key, but unlike that object, does not disable the switch flag {0x00C3, F_V0_V4, 0x0000400800780038, "TOHangceilingCave01*"}, // Caves signs. There appear to be no parameters. @@ -1657,11 +1541,10 @@ static const vector dat_object_definitions({ {0x00CB, F_V0_V4, 0x0000400000000010, "TORainbowCave01"}, // Floating jellyfish. Params: - // param1 = visibility radius; visible when any player is within this - // distance of the object + // param1 = visibility radius; visible when any player is within this distance of the object // param2 = move radius (according to debug strings) - // param3 = rebirth radius (according to debug strings); like param1, - // checks against all players, not only the local player + // param3 = rebirth radius (according to debug strings); like param1, checks against all players, not only the + // local player {0x00CC, F_V0_V4, 0x0000400030000010, "TOKurage"}, // Floating dragonfly. Params: @@ -1677,18 +1560,15 @@ static const vector dat_object_definitions({ {0x00CE, F_V0_V4, 0x0000400000000038, "TODoorCave03"}, // Robot recharge station. Params: - // param4 = quest register number; activates when this register - // contains a nonzero value; does not deactivate if it becomes zero - // again + // param4 = quest register number; activates when this register contains a nonzero value; does not deactivate if + // it becomes zero again {0x00CF, F_V0_V4, 0x00004008000000F8, "TOBind"}, // Caves cake shop. There appear to be no parameters. {0x00D0, F_V0_V4, 0x0000400000000020, "TOCakeshopCave01"}, - // Various solid rock objects used in the Cave areas. There are small, - // medium, and large variations of each, and for the 02 variations, there - // are also "Simple" variations (00D7-00D9). None of these objects take - // any parameters. + // Various solid rock objects used in the Cave areas. There are small, medium, and large variations of each, and + // for the 02 variations, there are also "Simple" variations (00D7-00D9). None of these objects take any params. {0x00D1, F_V0_V4, 0x0000400000000008, "TORockCaveS01"}, {0x00D2, F_V0_V4, 0x0000400000000008, "TORockCaveM01"}, {0x00D3, F_V0_V4, 0x00004FF000000008, "TORockCaveL01"}, @@ -1706,8 +1586,7 @@ static const vector dat_object_definitions({ // param1-3 = scale factors (visual only) // param4 = switch flag number // param5 high word = sound delay in frames after activate/deactivate - // param5 low word = model index for VR Temple / VR Spaceship? (there - // are only two: this word may be zero or nonzero) + // param5 low word = model index for VR Temple / VR Spaceship? (only matters if it's zero or nonzero) // param6 high word = sound activation mode: // 1 = play sound only when switch activated // anything else = play sound when activated and when deactivated @@ -1721,19 +1600,16 @@ static const vector dat_object_definitions({ // TODO: Are there more sounds available here on BB? {0x00DE, F_V2_V4, 0x00004FFC3FFB07FE, "TODummyKeyCave01"}, - // Breakable rocks, in small, medium, and large variations. All of these - // take the following parameter: + // Breakable rocks, in small, medium, and large variations. All of these take the following parameter: // param4 = switch flag number {0x00DF, F_V2_V4, 0x0000400000000008, "TORockCaveBL01"}, {0x00E0, F_V2_V4, 0x0000400000000010, "TORockCaveBL02"}, {0x00E1, F_V2_V4, 0x0000400000000020, "TORockCaveBL03"}, // Mines multi-switch door. Params: - // param4 = base switch flag number (the actual switch flags used are - // param4, param4 + 1, param4 + 2, etc.; if this is negative, the - // door is always unlocked) - // param5 = 4 - number of switch flags (so if e.g. door should require - // only 3 switch flags, set param5 to 1) + // param4 = base switch flag number (the actual switch flags used are param4, param4 + 1, param4 + 2, etc.; if + // this is negative, the door is always unlocked) + // param5 = 4 - number of switch flags (so if e.g. door should require only 3 switch flags, set param5 to 1) {0x0100, F_V0_V4, 0x00004000000000C0, "TODoorMachine01"}, // Mines floor button. The activation radius is always 10 units. Params: @@ -1744,8 +1620,7 @@ static const vector dat_object_definitions({ {0x0101, F_V0_V1, 0x00000000000000C0, "TOKeyMachine01"}, {0x0101, F_V2_V4, 0x00004FF0007B00C6, "TOKeyMachine01"}, - // Mines single-switch door, or Subterranean Desert door if in Episode 4. - // Params (for both object types): + // Mines single-switch door, or Subterranean Desert door if in Episode 4. Params (for both object types): // param4 = switch flag number {0x0102, F_V0_V4, 0x00000000000000C0, "TODoorMachine02"}, {0x0102, F_V4, 0x00004E0000000000, "__EP4_DOOR__"}, @@ -1757,21 +1632,18 @@ static const vector dat_object_definitions({ {0x0104, F_V0_V4, 0x00004008000000C0, "TOComputerMachine01"}, // Green monitor. Params: - // param4 = initial state? (clamped to [0, 3]; appears to cycle through - // those 4 values on its own) + // param4 = initial state? (clamped to [0, 3]; appears to cycle through those 4 values on its own) {0x0105, F_V0_V4, 0x00004008000000C0, "TOMonitorMachine01"}, - // Floating robot. Same params as 0x00CD (TODragonflyCave01), though it - // appears that some may have different scale factors or offsets (TODO). + // Floating robot. Same params as 0x00CD (TODragonflyCave01), though it appears that some may have different scale + // factors or offsets (TODO). {0x0106, F_V0_V4, 0x00004000000000C0, "TODragonflyMachine01"}, - // Floating rotating blue light (often appears next to doors). The light - // rotates about its vertical axis and floats up and down sinusoidally. - // Params: + // Floating rotating blue light (often appears next to doors). The light rotates about its vertical axis and floats + // up and down sinusoidally. Params: // param4 = float cycles per second (value is param4 * 0.1 + 1.0) // param5 = max float distance (value is param5 * 0.1 + 0.5) - // param6 = rotation speed in angle units per frame (0x10000 = 1 complete - // rotation) + // param6 = rotation speed in angle units per frame (0x10000 = 1 complete rotation) {0x0107, F_V0_V4, 0x00004000000000C0, "TOLightMachine01"}, // Self-destructing objects. Params: @@ -1780,47 +1652,38 @@ static const vector dat_object_definitions({ {0x0109, F_V0_V4, 0x00004000000000C0, "TOExplosiveMachine02"}, {0x010A, F_V0_V4, 0x00004000000000C0, "TOExplosiveMachine03"}, - // Spark machine. This looks like it's intended to appear in the bridge - // room in Mine 1, to create an effect of the columnar machines sparking. - // This is implemented as four columns that randomly change their - // visibility, intended to be in the same position as the map geometry. - // Each column has an accumulator value, which is initially zero. Every - // frame, the value (param1 - 0.98) is added to each column's accumulator - // and a random number between 0 and 1 is chosen; if the random number is - // less than the column's accumulator, its visibility state is changed and - // its accumulator is reset to zero. In this manner, param1 can be thought - // of as the frequency of state changes - 0.98 would mean they never change - // state, 1.98 would mean they change every frame. Params: + // Spark machine. This looks like it's intended to appear in the bridge room in Mine 1, to create an effect of the + // columnar machines sparking. This is implemented as four columns that randomly change their visibility, intended + // to be in the same position as the map geometry. Each column has an accumulator value, which is initially zero. + // Every frame, the value (param1 - 0.98) is added to each column's accumulator and a random number between 0 and 1 + // is chosen; if the random number is less than the column's accumulator, its visibility state is changed and its + // accumulator is reset to zero. In this manner, param1 can be thought of as the frequency of state changes - 0.98 + // would mean they never change state, 1.98 would mean they change every frame. Params: // param1 = state change accumulation per frame (value is param1 - 0.98) - // param2 = if <= 0, only one column flickers and the others are always - // visible; if > 0, all columns flicker + // param2 = if <= 0, only one column flickers and the others are always visible; if > 0, all columns flicker {0x010B, F_V0_V4, 0x00004000000000C0, "TOSparkMachine01"}, // Open stall with a spinning red light on either side. Params: // param2 = if > 0, a gray box is present in the left half of the stall {0x010C, F_V0_V4, 0x00004000000000C0, "TOHangerMachine01"}, - // Ruins entrance door (after Vol Opt). This object reads quest flags - // 0x2C, 0x2D, and 0x2E to determine the state of each seal on the door - // (for Forest, Caves, and Mines respectively). It then checks quest flag - // 0x2F; if this flag is set, then all seals are unlocked regardless of - // the preceding three flags' values. All of these flags are checked every - // frame, not only at construction time. - // No parameters. + // Ruins entrance door (after Vol Opt). This object reads quest flags 0x2C, 0x2D, and 0x2E to determine the state + // of each seal on the door (for Forest, Caves, and Mines respectively). It then checks quest flag 0x2F; if this + // flag is set, then all seals are unlocked regardless of the preceding three flags' values. All of these flags are + // checked every frame, not only at construction time. This object takes no parameters. {0x0130, F_V0_V4, 0x0000400000002000, "TODoorVoShip"}, // Ruins floor warp. Params: // param4 = destination floor - // param6 = color (negative = red, zero or positive = blue); if this is - // >= 0 in Challenge mode, the warp is destroyed immediately + // param6 = color (negative = red, zero or positive = blue); if this is >= 0 in Challenge mode, the warp is + // destroyed immediately {0x0140, F_V0_V4, 0x0000400000000700, "TObjGoalWarpAncient"}, // Ruins intra-area warp. Params: // param1-3 = destination (same as for TObjMapWarpForest) // param4 = destination angle (same as for TObjMapWarpForest) - // param5 = if negative, no warp lines render (only the floor pad - // appears) and the player cannot use the warp; if zero or positive, - // the warp functions normally + // param5 = if negative, no warp lines render (only the floor pad appears) and the player cannot use the warp; if + // zero or positive, the warp functions normally {0x0141, F_V0_V4, 0x0000400000000700, "TObjMapWarpAncient"}, // Ruins switch. Same parameters as 0x00C0 (TOKeyCave01). @@ -1838,15 +1701,14 @@ static const vector dat_object_definitions({ {0x0149, F_V0_V4, 0x0000400000000400, "TODoorAncient07"}, // Usually used in Ruins 3 // Ruins 4-player door. Params: - // param4 = base switch flag number (the actual switch flags used are - // param4, param4 + 1, param4 + 2, and param4 + 3); param4 is clamped - // to [0, 0xFC] + // param4 = base switch flag number (the actual switch flags used are param4, param4 + 1, param4 + 2, and param4 + // + 3); param4 is clamped to [0, 0xFC] // param6 = activation mode; same as for 0x00C1 (TODoorCave01) {0x014A, F_V0_V4, 0x0000400000000700, "TODoorAncient08"}, // Ruins 2-player door. Params: - // param4 = base switch flag number (the actual switch flags used are - // param4 and param4 + 1); param4 is clamped to [0, 0xFE] + // param4 = base switch flag number (the actual switch flags used are param4 and param4 + 1); param4 is clamped + // to [0, 0xFE] // param6 = activation mode; same as for 0x00C1 (TODoorCave01) {0x014B, F_V0_V4, 0x0000400000000700, "TODoorAncient09"}, @@ -1854,14 +1716,12 @@ static const vector dat_object_definitions({ // param1 = activation radius delta (actual radius is param1 + 50) // param4 = switch flag number // param5 = if negative, sensor is always on - // param6 = texture index; uses fs_obj_o_sensor01r if <= 0, uses - // fs_obj_o_sensor02r if positive; the two texture files are identical - // (at least on GC) so this has no user-visible effects + // param6 = texture index; uses fs_obj_o_sensor01r if <= 0, uses fs_obj_o_sensor02r if > 0; the two texture files + // are identical (at least on GC) so this has no user-visible effects {0x014C, F_V0_V4, 0x0000400000000700, "TOSensorAncient01"}, // Ruins laser fence switch. Params: - // param1 = if negative, switch's effect is temporary; if zero or - // positive, it's permanent + // param1 = if negative, switch's effect is temporary; if zero or positive, it's permanent // param4 = switch flag number // param5 = color (clamped to [0, 3]) {0x014D, F_V0_V4, 0x0000400000000700, "TOKeyAncient01"}, @@ -1874,52 +1734,45 @@ static const vector dat_object_definitions({ {0x0150, F_V0_V4, 0x0000400000000700, "TOFenceAncient03"}, // 4x4 {0x0151, F_V0_V4, 0x0000400000000700, "TOFenceAncient04"}, // 6x4 - // Ruins poison-spewing blob. This object is technically an item box, and - // drops an item when destroyed. Unlike most other item boxes, it cannot - // be specialized (ignore_def is always true). It cycles through the - // following 3 phases in order until it's destroyed: + // Ruins poison-spewing blob. This object is technically an item box, and drops an item when destroyed. Unlike most + // other item boxes, it cannot be specialized (ignore_def is always true). It cycles through the following 3 phases + // in order until it's destroyed: // Phase 0: idle (duration depends on param1 and players' positions) // Phase 1: preparing to spew poison (always lasts 60 frames) // Phase 2: spewing poison (duration specified by param2) // Params: - // param1 = maximum phase 0 duration in frames (value is param1 + 299; - // it advances to phase 1 early if a player is within 80 units of it) + // param1 = maximum phase 0 duration in frames (value is param1 + 299; it advances to phase 1 early if a player + // is within 80 units of it) // param2 = duration of phase 2 in frames (value is param2 + 209) - // param3 = poison radius squared (value is param3 + 399, so if param3 = - // 1 for example, the poison radius is 20 units) - // param6 = how often to create more particles during spewing phase (in - // frames; value is param6 + 4) + // param3 = poison radius squared (value is param3 + 399, so if param3 = 1 for example, the poison radius is 20) + // param6 = how often to create more particles during spewing phase (in frames; value is param6 + 4) {0x0152, F_V0_V4, 0x00004E000F800700, "TContainerAncient01"}, - // Ruins falling trap. Trap power seems to be scaled by difficulty - // (Normal = x1, Hard = x2, Very Hard = x3, Ultimate = x6). Params: + // Ruins falling trap. Trap power seems to be scaled by difficulty (Normal = x1, Hard = x2, Very Hard = x3, + // Ultimate = x6). Params: // param1 = trigger radius delta (value is (param1 / 2) + 30) // param2 = TODO (clamped below to 0) // param3 = TODO (clamped below to 1) - // param4 = TODO (seems it only matters if this is negative or not in - // the base class (TOTrap), but TOTrapAncient01 clamps it below to 0) - // param5 = TODO (clamped to [0, 5]; calls player->vtable[0x19] on - // explode unless this is 5) + // param4 = TODO (seems it only matters if this is negative or not in the base class (TOTrap), but + // TOTrapAncient01 clamps it below to 0) + // param5 = TODO (clamped to [0, 5]; calls player->vtable[0x19] on explode unless this is 5) // param6 = TODO (value is param6 + 30, multipled by 0.33 if offline) {0x0153, F_V0_V4, 0x0000400000780700, "TOTrapAncient01"}, // Ruins pop-up trap. Params: // param1 = trigger radius delta (value is (param1 / 2) + 30) // param4 = delay (value is param4 + 30; clamped below to 0) - // angle.z = hide body (positive = only the blue highlights appear; zero - // or negative = normal visibility) + // angle.z = hide body (positive = only the blue highlights appear; zero or negative = normal visibility) {0x0154, F_V0_V4, 0x0000400000000700, "TOTrapAncient02"}, // Ruins crystal monument. Same parameters as TOCapsuleAncient01. {0x0155, F_V0_V4, 0x0000400000000700, "TOMonumentAncient01"}, - // Non-Ruins monument. Sets a quest flag when activated. The quest flag - // depends on which area the object appears in: + // Non-Ruins monument. Sets a quest flag when activated. The quest flag depends on which area the object is in: // Mine 2 = 0x2E // Cave 2 = 0x2D // Any other area = 0x2C - // When all three of the above quest flags are active, this object also - // sets quest flag 0x2F. + // When all three of the above quest flags are active, this object also sets quest flag 0x2F. // There appear to be no parameters. {0x0156, F_V0_V4, 0x0000400000000094, "TOMonumentAncient02"}, @@ -1932,19 +1785,14 @@ static const vector dat_object_definitions({ {0x015E, F_V0_V4, 0x0000400000000700, "TOWreckAncient06"}, {0x015F, F_V0_V4, 0x0000400000000700, "TOWreckAncient07"}, - // 0x0160 constructs different objects depending on where it's used. On - // floor 0D (Vol Opt), it constructs TObjWarpBoss03; on other floors - // where it's valid, it constructs TObjFogCollisionPoison. - // TObjWarpBoss03 creates an invisible warp. This is used for the warp - // behind the door to Ruins after defeating Vol Opt. Params: + // Invisible cross-floor warp. This is used for the warp behind the door to Ruins after defeating Vol Opt, and is + // only available on that floor (on any other floor, 0x0160 constructs TObjFogCollisionPoison instead.) Params: // param4 = destination floor {0x0160, F_V0_V4, 0x0000400000002000, "TObjWarpBoss03"}, - // TObjFogCollisionPoison creates a switchable, foggy area that's visible - // and hurts the player if the switch flag isn't on. Params are the same - // as for 0x0018 (TObjFogCollisionSwitch), but there is also: - // param2 = poison power (scaled by difficulty: Normal = x1, Hard = x2, - // Very Hard = x3, Ultimate = x6) + // Switchable, foggy area that's visible and hurts the player if the switch flag isn't on. Params are the same as + // for 0x0018 (TObjFogCollisionSwitch), but there is also: + // param2 = poison power (scaled by difficulty: Normal = x1, Hard = x2, Very Hard = x3, Ultimate = x6) {0x0160, F_V0_V4, 0x00004FF030600700, "TObjFogCollisionPoison"}, // Ruins specialized box. Same parameters as 0x0088 (TObjContainerBase2). @@ -1953,8 +1801,7 @@ static const vector dat_object_definitions({ // Ruins random box. Same parameters as 0x0088 (TObjContainerBase2). {0x0162, F_V0_V4, 0x00004003007B0700, "TOContainerAncientItemRare"}, - // Ruins enemy boxes, disguised as either of the above two objects. - // Params: + // Ruins enemy boxes, disguised as either of the above two objects. Params: // param4 = event number {0x0163, F_V0_V4, 0x00004000007B0700, "TOContainerAncientEnemyCommon"}, {0x0164, F_V0_V4, 0x00004000007B0700, "TOContainerAncientEnemyRare"}, @@ -1969,12 +1816,11 @@ static const vector dat_object_definitions({ // Ruins pop-up trap with techs. Params: // param1 = trigger radius delta (value is (param1 / 2) + 30) // param2 = number of hits to destroy trap (clamped to [1, 256]) - // param3 = tech level modifier: + // param3 = tech level modifier (note: level is offset by 1, so a value of 0 means tech level 1): // Normal: level = param3 + 1 (clamped to [0, 14]) // Hard: level = (param3 * 2) + 1 (clamped to [0, 14]) // Very Hard: level = (param3 * 4) + 1 (clamped to [0, 14]) // Ultimate: level = (param3 * 6) + 1 (clamped to [0, 29]) - // (Note: level is offset by 1, so a value of 0 means tech level 1) // param4 = delay (value is param4 + 30; clamped below to 0) // param5 = switch flag number (negative = always active) // param6 = tech number: @@ -2013,8 +1859,7 @@ static const vector dat_object_definitions({ // param6 = TODO {0x0173, F_V0_V2, 0x0000000000004000, "TOSoulDF"}, - // Butterfly. This is a subclass of TODragonfly and takes the same params - // as 0x00CD (TODragonflyCave01), but also: + // Butterfly. This is a subclass of TODragonfly and takes the same params as 0x00CD (TODragonflyCave01), but also: // param6 = model number? (clamped to [0, 2]) {0x0174, F_V0_V2, 0x0000000000004000, "TOButterflyDF"}, @@ -2050,27 +1895,23 @@ static const vector dat_object_definitions({ // Visibility depends on the current season event in a complicated way: // If param5 <= 0, visible only when there's no season event // If param5 == 1 and param6 <= 0, visible during Wedding event - // If param5 == 2 and param6 <= 0, visible during Valentine's Day and - // White Day events + // If param5 == 2 and param6 <= 0, visible during Valentine's Day and White Day events // If none of the above, visible during Halloween event {0x0183, F_V3_V4, 0x0000400000008000, "__LOBBY_PIGEON__"}, {0x0183, F_EP3, 0x0000000000008002, "__LOBBY_PIGEON__"}, // Lobby butterfly. Params: // param4 = model number (only two models; <= 0 or > 0) - // TODO: Is this object's visibility affected by season events? It may - // only be affected by the event when the object loads, and not when the - // season is changed via the DA command. + // TODO: Is this object's visibility affected by season events? It may only be affected by the event when the + // object loads, and not when the season is changed via the DA command. {0x0184, F_V3_V4, 0x0000400000008000, "TObjButterflyLobby"}, {0x0184, F_EP3, 0x0000000000008002, "TObjButterflyLobby"}, - // Lobby rainbow. Visible only when there is no season event. There are - // no parameters. + // Lobby rainbow. Visible only when there is no season event. There are no parameters. {0x0185, F_V3_V4, 0x0000400000008000, "TObjRainbowLobby"}, {0x0185, F_EP3, 0x0000000000008002, "TObjRainbowLobby"}, - // Lobby pumpkin. Visible only during Halloween season event. There are - // no parameters. + // Lobby pumpkin. Visible only during Halloween season event. There are no parameters. {0x0186, F_V3_V4, 0x0000400000008000, "TObjKabochaLobby"}, {0x0186, F_EP3, 0x0000000000008000, "TObjKabochaLobby"}, @@ -2081,22 +1922,20 @@ static const vector dat_object_definitions({ {0x0187, F_V3_V4, 0x0000400000008000, "TObjStendGlassLobby"}, {0x0187, F_EP3, 0x0000000000008000, "TObjStendGlassLobby"}, - // Lobby red and white striped curtain. Visible only during the spring - // and summer season events (12 and 13). No parameters. + // Lobby red and white striped curtain. Visible only during the spring and summer season events (12 and 13). There + // are no parameters. {0x0188, F_V3_V4, 0x0000400000008000, "TObjCurtainLobby"}, {0x0188, F_EP3, 0x0000000000008000, "TObjCurtainLobby"}, - // Lobby wedding arch. Visible only during the wedding season event. No - // parameters. + // Lobby wedding arch. Visible only during the wedding season event. There are no parameters. {0x0189, F_V3_V4, 0x0000400000008000, "TObjWeddingLobby"}, {0x0189, F_EP3, 0x0000000000008000, "TObjWeddingLobby"}, - // Lobby snowy evergreen tree (Lobby 10). No parameters. + // Lobby snowy evergreen tree (Lobby 10). There are no parameters. {0x018A, F_V3_V4, 0x0000400000008000, "TObjTreeLobby"}, {0x018A, F_EP3, 0x0000000000008000, "TObjTreeLobby"}, - // Lobby aquarium (Lobby 5). Visible only when there is no season event. - // No parameters. + // Lobby aquarium (Lobby 5). Visible only when there is no season event. There are no parameters. {0x018B, F_V3_V4, 0x0000400000008000, "TObjSuisouLobby"}, {0x018B, F_EP3, 0x0000000000008000, "TObjSuisouLobby"}, @@ -2109,42 +1948,37 @@ static const vector dat_object_definitions({ {0x018C, F_V3_V4, 0x0000400000008000, "TObjParticleLobby"}, {0x018C, F_EP3, 0x0000000000008000, "TObjParticleLobby"}, - // Episode 3 lobby battle table. This object is responsible for the red - // panels on the floor next to the battle table that turn green when you - // step on them; it also shows the confirmation window and sends the - // necessary commands to the server. The actual table model and the non-lit - // parts of the floor panels are part of the lobby geometry, not this - // object. Params: + // Episode 3 lobby battle table. This object is responsible for the red panels on the floor next to the battle + // table that turn green when you step on them; it also shows the confirmation window and sends the necessary + // commands to the server. The actual table model and the non-lit parts of the floor panels are part of the lobby + // geometry, not this object. Params: // param4 = player count // 1 = 1 player (doesn't work properly - there's no way to confirm) // 2 = 2 players - // 3 = 3 players (unused, but works) + // 3 = 3 players (normally unused, but works) // 4 = 4 players // anything else = object doesn't load // param5 = table number (used in E4 and E5 commands) {0x018D, F_EP3, 0x0000000000008000, "TObjLobbyTable"}, - // Episode 3 lobby jukebox. No parameters. + // Episode 3 lobby jukebox. There are no parameters. {0x018E, F_EP3, 0x0000000000008000, "TObjJukeBox"}, - // Spaceship overhead camera with red light and annoying gear noises. There - // appear to be no parameters. + // Spaceship overhead camera with red light and annoying gear noises. There appear to be no parameters. {0x0190, F_V2_V4, 0x0000400000610000, "TObjCamera"}, // Short Spaceship wall. There appear to be no parameters. {0x0191, F_V2_V4, 0x0000400800610000, "TObjTuitate"}, // Spaceship door. Params: - // param4 = switch flag number (if this is negative, the door is always - // unlocked) + // param4 = switch flag number (if this is negative, the door is always unlocked) {0x0192, F_V2_V4, 0x0000400000610000, "TObjDoaEx01"}, // Tall Spaceship wall. There appear to be no parameters. {0x0193, F_V2_V4, 0x0000400800610000, "TObjBigTuitate"}, // Temple door. Params: - // param4 = switch flag number (if this is negative, the door is always - // unlocked) + // param4 = switch flag number (if this is negative, the door is always unlocked) {0x01A0, F_V2_V4, 0x00004000001A0000, "TODoorVS2Door01"}, // Temple rubble. None of these take any parameters. @@ -2156,70 +1990,60 @@ static const vector dat_object_definitions({ {0x01A6, F_V2_V4, 0x00004000001A0000, "TOVS2Wreck06"}, // Truncated conic monument // Temple breakable wall, which looks like 0x01A1 (TOVS2Wreck01). Params: - // param4 = number of hits, minus 256 for some reason (for example, for - // a 6-hit wall, this should be -250, or 0xFFFFFF06) + // param4 = number of hits, minus 256 for some reason (for example, for a 6-hit wall, this should be -250, or + // 0xFFFFFF06) {0x01A7, F_V2_V4, 0x00004000001A0000, "TOVS2Wall01"}, - // Lens flare enable/disable switch. This object triggers when the local - // player is within 20 units, and sets a global which determines whether - // objects of type 0x001E (__LENS_FLARE__) should render anything. - // Params: + // Lens flare enable/disable switch. This object triggers when the local player is within 20 units, and sets a + // global which determines whether objects of type 0x001E (__LENS_FLARE__) should render anything. Params: // param1 = if > 0, enable lens flare rendering; if <= 0, disable it // This object isn't constructed in split-screen mode. {0x01A8, F_V2_V4, 0x000041F1001A0000, "__LENS_FLARE_SWITCH_COLLISION__"}, // Rising bridges. Similar to 0x008F (TObjHashi). Params: - // param1 = extra depth when lowered (this is added to TObjHashiBase's - // 30 unit displacement if the bridge is lowered when constructed) + // param1 = extra depth when lowered (this is added to TObjHashiBase's 30 unit displacement if the bridge is + // lowered when constructed) // param2 = rise speed in units per frame // param4 = switch flag number {0x01A9, F_V2_V4, 0x00004000001A0000, "TObjHashiVersus1"}, // Small brown rising bridge {0x01AA, F_V2_V4, 0x00004000001A0000, "TObjHashiVersus2"}, // Long rising bridge // Multiplayer Temple/Spaceship doors. Params: - // param4 = base switch flag number (the actual switch flags used are - // param4, param4 + 1, param4 + 2, etc.; if this is negative, the - // door is always unlocked) + // param4 = base switch flag number (the actual switch flags used are param4, param4 + 1, param4 + 2, etc.; if + // this is negative, the door is always unlocked) // param5 = number of switch flags // param6 = synchronization mode: - // negative = when all switch flags are enabled, door is permanently - // unlocked via 6x0B even if some switch flags are disabled later - // zero or positive = door only stays unlocked while all of the - // switch flags are active and locks again when any are disabled - // (no effect in single-player offline mode; the negative behavior - // is used instead) + // negative = when all switch flags are enabled, door is permanently unlocked via 6x0B even if some switch + // flags are disabled later + // zero or positive = door only stays unlocked while all of the switch flags are active and locks again when + // any are disabled (no effect in single-player offline mode; the negative behavior is used instead) {0x01AB, F_V3_V4, 0x0000400000180000, "TODoorFourLightRuins"}, // Temple {0x01C0, F_V3_V4, 0x0000000000600000, "TODoorFourLightSpace"}, // Spaceship - // CCA item box. It seems this box type cannot be specialized. There are - // no parameters. + // CCA item box. It seems this box type cannot be specialized. There are no parameters. {0x0200, F_V3_V4, 0x000041FC4F800000, "TObjContainerJung"}, // CCA cross-floor warp. Params: // param4 = destination floor - // param6 = color (0 = blue, 1 = red); if this is 0 in Challenge mode, - // the warp is destroyed immediately + // param6 = color (0 = blue, 1 = red); if this is 0 in Challenge mode, the warp is destroyed immediately {0x0201, F_V3_V4, 0x0000400CFF800000, "TObjWarpJung"}, // CCA door. Params: - // param4 = base switch flag number (the actual switch flags used are - // param4, param4 + 1, param4 + 2, etc.; if this is negative, the - // door is always unlocked) + // param4 = base switch flag number (the actual switch flags used are param4, param4 + 1, param4 + 2, etc.; if + // this is negative, the door is always unlocked) // param5 = number of switch flags {0x0202, F_V3_V4, 0x0000400C0F800000, "TObjDoorJung"}, - // CCA item box. Same parameters as 0x0088 (TObjContainerBase2). - // In the Episode 4 Crater areas, this object constructs 0x0092 - // (TObjContainerBase) instead. + // CCA item box. Same parameters as 0x0088 (TObjContainerBase2). In the Episode 4 Crater areas, this object + // constructs 0x0092 (TObjContainerBase) instead. {0x0203, F_V3_V4, 0x0000400C4F800000, "TObjContainerJungEx"}, {0x0203, F_V4, 0x000001F000000000, "TObjContainerBase(0203)"}, - // CCA main door. This door checks quest flags 0x0046, 0x0047, and 0x0048 - // and opens when all are enabled. There are no parameters. + // CCA main door. This door checks quest flags 0x0046, 0x0047, and 0x0048 and opens when all are enabled. There are + // no parameters. {0x0204, F_V3_V4, 0x0000400000800000, "TODoorJungleMain"}, - // CCA main door switch. This switch sets one of the quest flags checked - // by 0x0204 (TODoorJungleMain). Params: + // CCA main door switch. This switch sets one of the quest flags checked by 0x0204 (TODoorJungleMain). Params: // param4 = quest flag index (0 = 0x0046, 1 = 0x0047, 2 = 0x0048) {0x0205, F_V3_V4, 0x0000400C0F800000, "TOKeyJungleMain"}, @@ -2228,30 +2052,26 @@ static const vector dat_object_definitions({ {0x0206, F_V3_V4, 0x000040040F800000, "TORockJungleS01"}, // Small rock {0x0207, F_V3_V4, 0x000040040F800000, "TORockJungleM01"}, // Small 3-rock wall - // Jungle large 3-rock wall. Unlike the above, this takes no parameters - // and cannot be opened. + // Jungle large 3-rock wall. Unlike the above, this takes no parameters and cannot be opened. {0x0208, F_V3_V4, 0x000040040F800000, "TORockJungleL01"}, // Jungle plant. Params: // param4 = model number? (clamped to [0, 1]) {0x0209, F_V3_V4, 0x000040040F800000, "TOGrassJungle"}, - // CCA warp outside main gate. Unlike other warps on Ragol, this one - // presents the player with a choice of areas: Jungle North (6), Mountain - // (8), or Seaside (9). Params: - // param6 = color (0 = blue, 1 = red); if this is 0 in Challenge mode, - // the warp is destroyed immediately + // CCA warp outside main gate. Unlike other warps on Ragol, this one presents the player with a choice of areas: + // Jungle North (6), Mountain (8), or Seaside (9). Params: + // param6 = color (0 = blue, 1 = red); if this is 0 in Challenge mode, the warp is destroyed immediately {0x020A, F_V3_V4, 0x0000400C0F800000, "TObjWarpJungMain"}, - // Background lightning generator. Each strike lasts for 11 frames and - // strikes at a random angle around the player. Params: + // Background lightning generator. Each strike lasts for 11 frames and strikes at a random angle around the player. + // Params: // param1 = lightning distance from player // param2 = lightning height // param3 = TODO (value is ((param3 / 32768) * 0.3) + 1) // param4 = minimum frames between strikes - // param5 = interval randomness (after each strike, a random number is - // chosen between param4 and (param4 + param5) to determine how many - // frames to wait until the next strike) + // param5 = interval randomness (after each strike, a random number is chosen between param4 and (param4 + + // param5) to determine how many frames to wait until the next strike) {0x020B, F_V3_V4, 0x0000400040800000, "TBGLightningCtrl"}, // Bird objects. Params: @@ -2265,14 +2085,12 @@ static const vector dat_object_definitions({ {0x020E, F_V3_V4, 0x0000400C0F800000, "TObjContainerJungEnemy"}, // Chain saw damage trap. Params: - // param2 = base damage (multiplied by difficulty: Normal = x1/5, Hard - // = x2/5, Very Hard = x3/5, Ultimate = x6/5) + // param2 = base damage (multiplied by difficulty: Normal = x1/5, Hard = x2/5, Very Hard = x3/5, Ultimate = x6/5) // param3 = model number (<= 0 for small saw, > 0 for large saw) // param4 = switch flag number (disabled when switch flag is enabled) // param5 high word = rotation range (16-bit angle) // param5 low word = rotation speed (angle units per frame) - // param6 high word = if nonzero, ignore rotation range and rotate in a - // full circle instead + // param6 high word = if nonzero, ignore rotation range and rotate in a full circle instead // param6 low word = delay between cycles (seconds) {0x020F, F_V3_V4, 0x0000400C3F800000, "TOTrapChainSawDamage"}, @@ -2282,9 +2100,8 @@ static const vector dat_object_definitions({ // param5-6 = same as 0x020F (TOTrapChainSawDamage) {0x0210, F_V3_V4, 0x0000400C3F800000, "TOTrapChainSawKey"}, - // TODO: Describe this object. It's a subclass of TODragonfly and has the - // same params as 0x00CD (TODragonflyCave01), though it appears that some - // may have different scale factors or offsets. + // TODO: Describe this object. It's a subclass of TODragonfly and has the same params as 0x00CD + // (TODragonflyCave01), though it appears that some may have different scale factors or offsets. {0x0211, F_V3_V4, 0x00004E0003800000, "TOBiwaMushi"}, {0x0211, F_EP3, 0x0000000000000002, "TOBiwaMushi"}, @@ -2309,17 +2126,14 @@ static const vector dat_object_definitions({ {0x0220, F_EP3, 0x0000000000008002, "TObjFish"}, // Seabed multiplayer doors. Params: - // param4 = base switch flag number (the actual switch flags used are - // param4, param4 + 1, param4 + 2, etc.; if this is negative, the - // door is always unlocked) + // param4 = base switch flag number (the actual switch flags used are param4, param4 + 1, param4 + 2, etc.; if + // this is negative, the door is always unlocked) // param5 = number of switch flags (clamped to [0, 4]) // param6 = synchronization mode: - // negative = when all switch flags are enabled, door is permanently - // unlocked via 6x0B even if some switch flags are disabled later - // zero or positive = door only stays unlocked while all of the - // switch flags are active and locks again when any are disabled - // (no effect in single-player offline mode; the negative behavior - // is used instead) + // negative = when all switch flags are enabled, door is permanently unlocked via 6x0B even if some switch + // flags are disabled later + // zero or positive = door only stays unlocked while all of the switch flags are active and locks again when + // any are disabled (no effect in single-player offline mode; the negative behavior is used instead) {0x0221, F_V3_V4, 0x0000400030000000, "TODoorFourLightSeabed"}, // Blue edges {0x0222, F_V3_V4, 0x0000400030000000, "TODoorFourLightSeabedU"}, @@ -2332,9 +2146,8 @@ static const vector dat_object_definitions({ // param5 = model number (clamped to [0, 2]) {0x0224, F_V3_V4, 0x0000400030000000, "TObjSeabedSuisoBrakable"}, - // Small floating robots. These are subclasses of TODragonfly and have - // the same params as 0x00CD (TODragonflyCave01), though it appears that - // some may have different scale factors or offsets (TODO). + // Small floating robots. These are subclasses of TODragonfly and have the same params as 0x00CD + // (TODragonflyCave01), though it appears that some may have different scale factors or offsets (TODO). {0x0225, F_V3_V4, 0x0000400030000000, "TOMekaFish00"}, // Blue {0x0226, F_V3_V4, 0x0000400030000000, "TOMekaFish01"}, // Red @@ -2342,8 +2155,8 @@ static const vector dat_object_definitions({ // param4 = model number (clamped to [0, 4]) {0x0227, F_V3_V4, 0x0000400030000000, "__DOLPHIN__"}, - // Seabed capturing trap, similar to 0x0153 (TOTrapAncient01) in - // function. Triggers when a player is within 15 units. Params: + // Seabed capturing trap, similar to 0x0153 (TOTrapAncient01) in function. Triggers when a player is within 15 + // units. Params: // param1 = TODO (clamped to [0.1, 10]) // param4 = hold time after trigger (in seconds; clamped to [1, 60]) // param5 = hide in split-screen: @@ -2352,28 +2165,25 @@ static const vector dat_object_definitions({ // param6 = same as param5 from 0x0153 (TOTrapAncient01) {0x0228, F_V3_V4, 0x0000400C3F800000, "TOTrapSeabed01"}, - // VR link object. This object is destroyed immediately in Challenge mode - // and split-screen mode. Same parameters as 0x008D (TOCapsuleAncient01). + // VR link object. This object is destroyed immediately in Challenge mode and split-screen mode. Same parameters as + // 0x008D (TOCapsuleAncient01). {0x0229, F_V3_V4, 0x0000400FFFF80000, "TOCapsuleLabo"}, - // Alias for 0x0001 (TObjParticle). The constructor function is exactly - // the same as for 0x0001, so this object has all the same paarameters - // and behavior as that object. + // Alias for 0x0001 (TObjParticle). The constructor function is exactly the same as for 0x0001, so this object has + // all the same paarameters and behavior as that object. {0x0240, F_V3_V4, 0x0000400040000000, "TObjParticle"}, - // Teleporter after Barba Ray. This object behaves exactly the same as - // 0x0002 (TObjAreaWarpForest), except it's invisible until the boss is - // defeated. + // Teleporter after Barba Ray. This object behaves exactly the same as 0x0002 (TObjAreaWarpForest), except it's + // invisible until the boss is defeated. {0x0280, F_V3_V4, 0x0000400100000000, "__BARBA_RAY_TELEPORTER__"}, // TODO: Describe this object. There appear to be no parameters. {0x02A0, F_V3_V4, 0x0000400200000000, "TObjLiveCamera"}, - // Gee nest. This object is technically an item box, and drops an item - // when destroyed. Unlike most other item boxes, it cannot be specialized - // (ignore_def is always true). Params are the same as for 0x0152 + // Gee nest. This object is technically an item box, and drops an item when destroyed. Unlike most other item + // boxes, it cannot be specialized (ignore_def is always true). Params are the same as for 0x0152 // (TContainerAncient01), but there is also: - // angle.z = number of hits to destroy + // angle.z = number of hits required to destroy {0x02B0, F_V3_V4, 0x00004E0C0F800700, "TContainerAncient01R"}, // Lab objects. None of these take any parameters. @@ -2391,47 +2201,37 @@ static const vector dat_object_definitions({ {0x02B6, F_EP3, 0x0000000000000001, "TObjLaboDesignBase(5)"}, // Long table // Game Boy Advance. Params: - // param4 = quest label to call when activated (inherited from - // TObjMesBase) - // param6 = type (clamped to [0, 1]; 0 = "QUEST", 1 = "RICO") - // (inherited from TObjMesBase) + // param4 = quest label to call when activated (inherited from TObjMesBase) + // param6 = type (clamped to [0, 1]; 0 = "QUEST", 1 = "RICO") (inherited from TObjMesBase) {0x02B7, F_GC, 0x0000000000040001, "TObjGbAdvance"}, - // Like TObjQuestColA (TODO: In what ways is it different?). Parameters - // are the same as for TObjQuestCol, but also: + // Like TObjQuestColA (TODO: In what ways is it different?). Parameters are the same as for TObjQuestCol, but also: // param2 = TODO - // param5 = quest script manager to use (zero or negative = quest, - // positive = free play) + // param5 = quest script manager to use (zero or negative = quest, positive = free play) {0x02B8, F_V3_V4, 0x00006FFFFFFC7FFF, "TObjQuestColALock2"}, {0x02B8, F_EP3, 0x0000000000000001, "TObjQuestColALock2"}, - // Like 0x0003 (TObjMapWarpForest), but is invisible and automatically - // warps players when they enter its radius. This is used to simulate - // floor warps in the Control Tower. Has the same parameters as - // TObjMapWarpForest, but also: - // param5 = destination "floor" number (this is an intra-map warp and - // doesn't actually change floors; the "floor" number is only visual) - // param6 = if <= 0, shows "floor" number (param5 formatted as "%xF") - // after warp; if > 0, param5 is ignored + // Like 0x0003 (TObjMapWarpForest), but is invisible and automatically warps players when they enter its radius. + // This is used to simulate floor warps in the Control Tower. Has the same params as TObjMapWarpForest, but also: + // param5 = destination "floor" number (this is an intra-map warp and doesn't actually change floors; the "floor" + // number is only visual) + // param6 = if <= 0, shows "floor" number (param5 formatted as "%xF") after warp; if > 0, param5 is ignored {0x02B9, F_V3_V4, 0x00007FFC3FFF78FF, "TObjMapForceWarp"}, {0x02B9, F_EP3, 0x0000000000000001, "TObjMapForceWarp"}, - // Behaves like 0x0012 (TObjQuestCol), but also has the param5 behavior - // from 0x02B8 (TObjQuestColALock2). + // Behaves like 0x0012 (TObjQuestCol), but also has the param5 behavior from 0x02B8 (TObjQuestColALock2). {0x02BA, F_V3_V4, 0x00006FFFFFFC7FFF, "TObjQuestCol2"}, {0x02BA, F_EP3, 0x0000000000000001, "TObjQuestCol2"}, - // Episode 2 Lab door with glass window. Same parameters as - // TODoorLaboNormal, except param5 is unused. + // Episode 2 Lab door with glass window. Same parameters as TODoorLaboNormal, except param5 is unused. {0x02BB, F_V3_V4, 0x0000400000040000, "TODoorLaboNormal"}, - // Episode 2 ending movie warp (used in final boss arenas after the boss - // is defeated). Same params as 0x001C (TObjAreaWarpEnding). + // Episode 2 ending movie warp (used in final boss arenas after the boss is defeated). Same params as 0x001C + // (TObjAreaWarpEnding). {0x02BC, F_V3_V4, 0x0000400080000000, "TObjAreaWarpEndingJung"}, - // Warp to another location on the same map. Used for the Lab/city warp. - // This warp is visible in all game modes, but cannot be used in Episode - // 1, Battle mode, or Challenge mode. Params: + // Warp to another location on the same map. Used for the Lab/city warp. This warp is visible in all game modes, + // but cannot be used in Episode 1, Battle mode, or Challenge mode. Params: // param1-3 = destination (same as for TObjMapWarpForest) // param4 = destination angle (same as for TObjMapWarpForest) // param6 = destination text (clamped to [0, 2]): @@ -2440,8 +2240,7 @@ static const vector dat_object_definitions({ // 02 = "Lab" {0x02BD, F_V3_V4, 0x0000400000040000, "TObjLaboMapWarp"}, - // This object is used internally by Episode 3 during battles as the - // visual implementation for some overlay tiles. + // This object is used internally by Episode 3 during battles as the visual implementation for some overlay tiles. // Params: // param1-3 = TODO // param4 = model number: @@ -2465,23 +2264,20 @@ static const vector dat_object_definitions({ // param6 low byte = TODO {0x02D0, F_EP3, 0x0000000000000002, "TObjKazariCard"}, - // Effects visible in the central column in the Morgue when cards - // transform. There appear to be no parameters. + // Effects visible in the central column in the Morgue when cards transform. There appear to be no parameters. {0x02D1, F_EP3, 0x0000000000000001, "TObj_FloatingCardMaterial_Dark"}, {0x02D2, F_EP3, 0x0000000000000001, "TObj_FloatingCardMaterial_Hero"}, - // Morgue warps. These don't actually do anything; they just look like a - // warp. The actual warping is done by another object (TObjCityAreaWarp - // for the lobby teleporter, or TShopGenerator for the battle counter). - // TObjCardCityMapWarp takes no parameters. + // Morgue warps. These don't actually do anything; they just look like a warp. The actual warping is done by + // another object (TObjCityAreaWarp for the lobby teleporter, or TShopGenerator for the battle counter). These take + // no parameters. {0x02D3, F_EP3, 0x0000000000000001, "TObjCardCityMapWarp(0)"}, // Battle counter warp (blue lines) {0x02D9, F_EP3, 0x0000000000000001, "TObjCardCityMapWarp(1)"}, // Battle counter warp (green lines; unused) {0x02E3, F_EP3, 0x0000000000000001, "TObjCardCityMapWarp(2)"}, // Lobby warp (yellow lines) - // Morgue doors. None of these take any parameters. Unsurprisingly, the - // _Closed variants don't open. The _Closed variants also have a red light - // in the center instead of a blue light. Curiously, the (3) variant is - // opaque when _Closed, unlike the other _Closed doors. + // Morgue doors. Unsurprisingly, the closed variants don't open. The closed variants also have a red light in the + // center instead of a blue light. Curiously, the (3) variant is opaque when closed, unlike the other closed doors. + // None of these take any parameters. {0x02D4, F_EP3, 0x0000000000000001, "TObjCardCityDoor(0)"}, // Yellow V-pattern (to deck edit room) {0x02D5, F_EP3, 0x0000000000000001, "TObjCardCityDoor(1)"}, // Blue V-pattern (to battle entry counter) {0x02D8, F_EP3, 0x0000000000000001, "TObjCardCityDoor(2)"}, // Green V-pattern (unused) @@ -2510,30 +2306,25 @@ static const vector dat_object_definitions({ // param5 = TODO (value is param5 % 7) {0x02D6, F_EP3, 0x0000000000000002, "TObjKazariGeyserMizu"}, - // TODO: Describe this object. It appears to be created by many creatures - // and probably SCs as well, but it's not obvious what it's used for, - // since the logic of tiles being blocked or free is implemented in - // TCardServer, which doesn't interact with this object. Further research - // is needed here. Params: + // TODO: Describe this object. It appears to be created by many creatures and probably SCs as well, but it's not + // obvious what it's used for, since the logic of tiles being blocked or free is implemented in TCardServer, which + // doesn't interact with this object. Further research is needed here. Params: // param1-3 = TODO // param4 = TODO (expected to be 0 or 1) {0x02D7, F_EP3, 0x0000000000000002, "TObjSetCardColi"}, - // Floating robots, presumably. These are both subclasses of 0x0106 - // (TODragonflyMachine01) and take all the same params as that object. + // Floating robots, presumably. These are both subclasses of 0x0106 (TODragonflyMachine01) and take all the same + // params as that object. {0x02DA, F_EP3, 0x0000000000000001, "TOFlyMekaHero"}, {0x02DB, F_EP3, 0x0000000000000001, "TOFlyMekaDark"}, - // Lobby banner or model display object. This implements display of media - // sent with the B9 command. Params: + // Lobby banner or model display object. This implements display of media sent with the B9 command. Params: // param1-3 = scale factors (x, y, z) - // param4 = index into location bit field (0-31 where 0 is the least- - // significant bit; see Episode3LobbyBanners in config.example.json - // for the bits' meanings) - // param5 = per-axis mirror flags (the low 3 nybbles of this value - // specify whether to invert each axis of the model; if any nybble is 1 - // then the model is inverted along the corresponding axis; the lowest - // nybble corresponds to the x axis) + // param4 = index into location bit field (0-31 where 0 is the least-significant bit; see Episode3LobbyBanners in + // config.example.json for the bits' meanings) + // param5 = per-axis mirror flags (the low 3 nybbles of this value specify whether to invert each axis of the + // model; if any nybble is 1 then the model is inverted along the corresponding axis; the lowest nybble + // corresponds to the x axis) {0x02E4, F_EP3, 0x0000000000008001, "TObjSinBoardCard"}, // Morgue info screen. Params: @@ -2542,9 +2333,8 @@ static const vector dat_object_definitions({ // 1 = short, blue, horizontal-scrolling {0x02E5, F_EP3, 0x0000000000000001, "TObjCityMoji"}, - // Like TObjCardCityMapWarp(2) (the warp to the lobby from the Morgue) - // but doesn't render the circles. Used in offline mode where that warp - // is disabled. No parameters. + // Like TObjCardCityMapWarp(2) (the warp to the lobby from the Morgue) but doesn't render the circles. Used in + // offline mode where that warp is disabled. There are no parameters. {0x02E6, F_EP3, 0x0000000000000001, "TObjCityWarpOff"}, // Small flying robot. There appear to be no parameters. @@ -2554,8 +2344,7 @@ static const vector dat_object_definitions({ // param4 = TODO (used in vtable[0x0E]) {0x02E8, F_EP3, 0x0000000000000001, "__UNKNOWN_02E8__"}, - // Episode 4 light source. - // TODO: Find and document this object's parameters. + // Episode 4 light source. TODO: Find and document this object's parameters. {0x0300, F_V4, 0x00005FF000000000, "__EP4_LIGHT__"}, // Wilds/Crater cactus. Params: @@ -2575,19 +2364,17 @@ static const vector dat_object_definitions({ {0x0303, F_V4, 0x00004FF000000000, "__WILDS_CRATER_BROWN_ROCK_DESTRUCTIBLE__"}, // TODO: Construct this object and see what it is. Params: - // param4 = object identifier (must be in range [0, 15]; used in 6xD4 - // command) + // param4 = object identifier (must be in range [0, 15]; used in 6xD4 command) {0x0340, F_V4, 0x0000400000000000, "__UNKNOWN_0340__"}, - // TODO: Construct this object and see what it is. It looks like some - // kind of child object of 0340. Params: - // param4 = object identifier (must be in range [0, 15]; used in 6xD4 - // command; looks like it should match an existing 0340's identifier) + // TODO: Construct this object and see what it is. It looks like some kind of child object of 0340. Params: + // param4 = object identifier (must be in range [0, 15]; used in 6xD4 command; looks like it should match an + // existing 0340's identifier) // param5 = child index? (must be in range [0, 3]) {0x0341, F_V4, 0x0000400000000000, "__UNKNOWN_0341__"}, - // Poison plant. Base damage is 10 (Normal), 20 (Hard), 30 (Very Hard), - // or 60 (Ultimate). There appear to be no parameters. + // Poison plant. Base damage is 10 (Normal), 20 (Hard), 30 (Very Hard), or 60 (Ultimate). There appear to be no + // parameters. {0x0380, F_V4, 0x00004E0000000000, "__POISON_PLANT__"}, // TODO: Describe this object. Params: @@ -2630,29 +2417,24 @@ static const vector dat_object_definitions({ // param6 = hitbox type (0 = rectangular, anything else = cylindrical) {0x0388, F_V4, 0x00004E0000000000, "__UNKNOWN_0388__"}, - // Game flag set/clear zone. This sets and clears game flags (the flags - // sent in 6x0A) when the player enters the object's hitbox. Params: + // Game flag set/clear zone. This sets and clears game flags (the flags sent in 6x0A) when the player enters the + // object's hitbox. Params: // param1-3 = same as for 0x0388 // param4 = game flags to set (low 8 bits only) // param5 = game flags to clear (low 8 bits only) // param6 = same as for 0x0388 - // There appears to be a bug that causes the game to always set all 8 of - // the low game flags, regardless of the value of param4. The clearing - // logic (param5) appears to work correctly. {0x0389, F_V4, 0x0000400000000000, "__GAME_FLAG_SET_CLEAR_ZONE__"}, - // HP drain zone. When a player is within this object's hitbox, it - // subtracts 0.66% of the player's current HP at a regular interval. The - // amount of damage per interval is capped below at 1 HP, so it will - // always do a nonzero amount of damage each time. Params: + // HP drain zone. When a player is within this object's hitbox, it subtracts 0.66% of the player's current HP at a + // regular interval. The amount of damage per interval is capped below at 1 HP, so it will always do a nonzero + // amount of damage each time. Params: // param1-3 = same as for 0x0388 // param5 = interval (in frames) between damage applications // param6 = same as for 0x0388 {0x038A, F_V4, 0x0000400000000000, "__HP_DRAIN_ZONE__"}, - // Falling stalactite. Activates when any player is within 50 units. Base - // damage is 100 on Normal, 200 on Hard, 300 on Very Hard, or 600 on - // Ultimate. There appear to be no parameters. + // Falling stalactite. Activates when any player is within 50 units. Base damage is 100 on Normal, 200 on Hard, 300 + // on Very Hard, or 600 on Ultimate. There appear to be no parameters. {0x038B, F_V4, 0x00004E0000000000, "__FALLING_STALACTITE__"}, // Solid desert plant. Params: @@ -2666,16 +2448,13 @@ static const vector dat_object_definitions({ // 1 = standard random item (ignore_def = 1) // 2 = customized item (ignore_def = 0) // 3 = trigger set event - // If param1 is 0 or 1, no other parameters are used. (In the case of 1, - // param3-6 are sent to the server in the 6xA2 command; however, the - // standard implementation ignores them.) - // If param1 is 2, the other parameters have the same meanings as for - // 0x0088 (TObjContainerBase2). + // If param1 is 0 or 1, no other parameters are used. (In the case of 1, param3-6 are sent to the server in the + // 6xA2 command; however, the standard implementation ignores them.) + // If param1 is 2, the other parameters have the same meanings as for 0x0088 (TObjContainerBase2). // If param1 is 3, the event number is specified in param4. {0x038D, F_V4, 0x00004E0000000000, "__DESERT_CRYSTALS_BOX__"}, - // Episode 4 test door. param4 and param6 are the same as for 0x0056 - // (TODoorLabo). + // Episode 4 test door. param4 and param6 are the same as for 0x0056 (TODoorLabo). {0x038E, F_V4, 0x0000400000000000, "__EP4_TEST_DOOR__"}, // Beehive. Params: @@ -2684,8 +2463,7 @@ static const vector dat_object_definitions({ // param4 = model number (clamped to [0, 1]) {0x038F, F_V4, 0x00004E0000000000, "__BEEHIVE__"}, - // Episode 4 test particles. Generates particles at a specific location - // (TODO) at a regular interval. Params: + // Episode 4 test particles. Generates particles at a specific location (TODO) at a regular interval. Params: // angle.x = TODO // angle.y = TODO // param1 = particle distance? (TODO) @@ -2693,8 +2471,7 @@ static const vector dat_object_definitions({ // param4 = frames between effects {0x0390, F_V4, 0x00004E0000000000, "__EP4_TEST_PARTICLE__"}, - // Heat (implemented as a type of poison fog). Has the same parameters as - // TObjFogCollisionPoison. + // Heat (implemented as a type of poison fog). Has the same parameters as TObjFogCollisionPoison. {0x0391, F_V4, 0x00004E0000000000, "__HEAT__"}, // Episode 4 boss egg. There appear to be no parameters. @@ -2708,18 +2485,14 @@ static const vector dat_object_definitions({ static const vector dat_enemy_definitions({ // This is newserv's canonical definition of map enemy and NPC types. - // Enemies and NPCs take a similar arguments structure as objects: - // objects use ObjectSetEntry, enemies use EnemySetEntry. Unlike objects, - // some IDs are reused across game versions or areas, so the same enemy - // type can generate a completely different entity on different game - // versions. This is why some enemies have multiple entries with the same - // type and different names. + // Enemies and NPCs take a similar arguments structure as objects: objects use ObjectSetEntry, enemies use + // EnemySetEntry. Like objects, some IDs are reused across game versions or areas, so the same enemy type can + // generate a completely different entity on different game versions. This is why some enemies have multiple + // entries with the same type and different names. - // Some enemies have params that the game's code references, but only in - // places where their effects can't be seen (for example, in normally- - // unused debug menus). These may have been used to test frame-by-frame - // animations for some enemies; see TObjEneMe3Shinowa_v76 for an example - // of this usage. The enemies with params like this are: + // Some enemies have params that the game's code references, but only in places where their effects can't be seen + // (for example, in normally-unused debug menus). These may have been used to test frame-by-frame animations for + // some enemies; see TObjEneMe3Shinowa_v76 for an example of this usage. The enemies with params like this are: // - TObjEneMe3ShinowaReal (param3, param4) // - TObjEneDf2Bringer (param1, param2) // - TObjEneRe7Berura (param1, param2) @@ -2727,36 +2500,28 @@ static const vector dat_enemy_definitions({ // - TBoss5Gryphon (param1, param2) // - TBoss2DeRolLe (param1, param2) // - TBoss8Dragon (param1, param2) - // - TObjEneBm5GibonU (param4, param5; these params also have non-debug - // meanings) - // - TObjEneMorfos (oaram1, param2; these params also have non-debug - // meanings) + // - TObjEneBm5GibonU (param4, param5; these params also have non-debug meanings) + // - TObjEneMorfos (oaram1, param2; these params also have non-debug meanings) // NPCs. Params: // param1 = action parameter (depends on param6; see below) - // param2 = visibility register number (if this is > 0, the NPC will - // only be visible when this register is nonzero; if this is >= 1000, - // the effective register is param2 - 1000 and register values for - // both param2 and param3 are read from the free play script + // param2 = visibility register number (if this is > 0, the NPC will only be visible when this register is + // nonzero; if this is >= 1000, the effective register is param2 - 1000 and register values for both param2 and + // param3 are read from the free play script environment instead of the quest script environment) + // param3 = hide override register number (if this is > 0, the NPC will not be visible when this register is + // nonzero, regardless of the state of the register specified by param2; if this is >= 1000, the effective + // register is param3 - 1000 and register values for both param2 and param3 are read from the free play script // environment instead of the quest script environment) - // param3 = hide override register number (if this is > 0, the NPC will - // not be visible when this register is nonzero, regardless of the - // state of the register specified by param2; if this is >= 1000, the - // effective register is param3 - 1000 and register values for both - // param2 and param3 are read from the free play script environment - // instead of the quest script environment) - // param4 = object number ("character ID" in qedit; if this is outside - // the range [100, 999], the quest label in param5 is called in the - // free play script instead of the quest script) - // param5 = quest label to call when interacted with (if zero, NPC does - // nothing upon interaction) + // param4 = object number ("character ID" in qedit; if this is outside the range [100, 999], the quest label in + // param5 is called in the free play script instead of the quest script) + // param5 = quest label to call when interacted with (if zero, NPC does nothing upon interaction) // param6 = specifies what NPC does when idle: // 0 = stand still (param1 is ignored) // 1 = walk around randomly (param1 = max walk distance from home) // 2 = TODO (Ep3 only; appears to be unused) // 3 = TODO (Ep3 only; appears to be unused) - // TODO: setting param4 to 0 changes something else about the NPC; figure - // out what this does (see TObjNpcBase_v57_set_config_from_params) + // TODO: setting param4 to 0 changes something else about the NPC; figure out what this does (see + // TObjNpcBase_v57_set_config_from_params) {0x0001, F_V0_V4, 0x0000200000000001, "TObjNpcFemaleBase"}, // Woman with red hair and purple outfit {0x0001, F_EP3, 0x0000000000000001, "TObjNpcFemaleBase"}, // Woman with red hair and purple outfit {0x0002, F_V0_V4, 0x0000200000000001, "TObjNpcFemaleChild"}, // Shorter version of the above @@ -2837,8 +2602,8 @@ static const vector dat_enemy_definitions({ {0x00F6, F_V3_V4, 0x000000080F840000, "TObjNpcNgcBase(0x00F6)"}, // TODO {0x00F7, F_V3_V4, 0x0000000000040000, "TObjNpcNgcBase(0x00F7)"}, // Nol {0x00F8, F_V3_V4, 0x0000000000040000, "TObjNpcNgcBase(0x00F8)"}, // Elly - {0x00F9, F_V3_V4, 0x0000000000040000, "TObjNpcNgcBase(0x00F9)"}, // Woman with cyan hair down the ramp from Ep2 Medical Center - {0x00FA, F_V3_V4, 0x0000000000040000, "TObjNpcNgcBase(0x00FA)"}, // Woman with bright red hair down the ramp from Ep2 Medical Center + {0x00F9, F_V3_V4, 0x0000000000040000, "TObjNpcNgcBase(0x00F9)"}, // Woman with cyan hair + {0x00FA, F_V3_V4, 0x0000000000040000, "TObjNpcNgcBase(0x00FA)"}, // Woman with bright red hair {0x00FB, F_V3_V4, 0x0000000000040000, "TObjNpcNgcBase(0x00FB)"}, // Man with blue hair near the Ep2 Medical Center {0x00FC, F_V3_V4, 0x0000000000040000, "TObjNpcNgcBase(0x00FC)"}, // Man in room next to Ep2 Hunter's Guild {0x00FD, F_V3_V4, 0x000000040F840000, "TObjNpcNgcBase(0x00FD)"}, // TODO @@ -2848,13 +2613,10 @@ static const vector dat_enemy_definitions({ {0x0110, F_EP3, 0x0000000000000001, "TObjNpcWalkingMeka_Hero"}, // Small talking robot in Morgue {0x0111, F_EP3, 0x0000000000000001, "TObjNpcWalkingMeka_Dark"}, // Small talking robot in Morgue - // Episode 3 scientist and aide NPCs. These NPCs take all the same params - // as the NPCs defined above, but also: - // angle.x = model number (clamped to [0, 3] for scientists, [0, 2] for - // aides) - // The two type values for scientists (00D4 and 00D5) are direct aliases - // for each other; there is no difference between their in-game appearance - // or behavior. + // Episode 3 scientist and aide NPCs. These NPCs take all the same params as the NPCs defined above, but also: + // angle.x = model number (clamped to [0, 3] for scientists, [0, 2] for aides) + // The two type values for scientists (00D4 and 00D5) are direct aliases for each other; there is no difference + // between their in-game appearance or behavior. {0x00D4, F_EP3, 0x0000000000000001, "TObjNpcHeroScientist"}, {0x00D5, F_EP3, 0x0000000000000001, "TObjNpcHeroScientist"}, {0x0112, F_EP3, 0x0000000000000001, "TObjNpcHeroAide"}, @@ -2866,19 +2628,14 @@ static const vector dat_enemy_definitions({ // param6 high byte = NPC index in npcplayerchar.dat {0x0118, F_V4, 0x00007FF000000000, "__QUEST_NPC__"}, - // Enemy that behaves like an NPC. Has all the same params as the - // standard NPC types, but also: + // Enemy that behaves like an NPC. Has all the same params as the standard NPC types, but also: // angle.x = definition index - // The definition index is an integer from 0 to 15 (decimal) specifying - // which model, animations, and hitbox to use. The available choices depend - // on which assets are loaded, which in turn depend on the area (not floor) - // in which the NPC appears. To choose the right definition index, first - // look up the enemy you want in the models list below, then find the - // corresponding number in the areas table below that, and use the (zero- - // based) index of the number in that table for angle.x. For example, to - // place a Sinow Gold in Mine 2, angle.x should be 8 since Sinow Gold is - // 27, and there are 8 other values before 27 in the Mine 2 list. - // The available models are: + // The definition index is an integer from 0 to 15 (decimal) specifying which model, animations, and hitbox to use. + // The available choices depend on which assets are loaded, which in turn depend on the area (not floor) in which + // the NPC appears. To choose the right definition index, first look up the enemy you want in the models list + // below, then find the corresponding number in the areas table below that, and use the (zero-based) index of the + // number in that table for angle.x. For example, to place a Sinow Gold in Mine 2, angle.x should be 8 since Sinow + // Gold is 27, and there are 8 other values before 27 in the Mine 2 list. The available models are: // 01: Box (appearance depends on area) // 02: Booma (Ep1/2), Boota (Ep4) // 03: Gobooma (Ep1/2), Ze Boota (Ep4) @@ -2903,9 +2660,8 @@ static const vector dat_enemy_definitions({ // 16: Dark Bringer // 17: Canadine // 18: Canune - // 19: Dark Gunner (must be constructed after a Dark Gunner enemy, since - // the definition is populated in the enemy constructor, not in the - // asset loader) + // 19: Dark Gunner (must be constructed after a Dark Gunner enemy, since the definition is populated in the enemy + // constructor, not in the asset loader) // 1A: Delsaber // 1B: So Dimenian (Ep1/2), Goran (Ep4) // 1C: La Dimenian (Ep1/2), Pyro Goran (Ep4) @@ -2999,8 +2755,7 @@ static const vector dat_enemy_definitions({ // 21 (Gol Dragon): (none) // 22 (Seaside Night): 05 06 0C 0D 0E 0F 10 11 12 2C 2E 3B 3E 3F 45 4F // 23 (Tower): 0C 0D 37 3B 41 42 43 44 46 4E - // Episode 4 (note that these are not usable without a client patch, - // since this NPC is only available on Pioneer 2 in Episode 4): + // Episode 4 (these are not usable without a client patch, since this NPC is only available on Pioneer 2): // 24 (Crater East): 02 03 04 05 06 09 0A 22 32 46 // 25 (Crater West): 02 03 04 05 06 09 0A 22 32 46 // 26 (Crater South): 02 03 04 05 06 09 0A 22 32 46 @@ -3012,26 +2767,23 @@ static const vector dat_enemy_definitions({ // 2C (Saint-Milion): 38 39 3A 3B 3C 3D 3E 3F 40 // 2D (Pioneer 2): (none) // 2E (Test area): 01 02 09 0A 22 32 38 39 3A 3B 3C 3D 3E 3F 40 42 - // This NPC exists in Episode 3, but is only available in the Morgue and in - // the lobby. There are no available models in those areas, which makes it - // essentially useless. + // This NPC exists in Episode 3, but is only available in the Morgue and in the lobby. There are no available + // models in those areas, which makes it essentially useless. {0x0033, F_V3_V4, 0x0000200FFFFFFFFF, "TObjNpcEnemy"}, {0x0033, F_EP3, 0x0000000000008001, "TObjNpcEnemy"}, // Hildebear. Params: // param1 = initial location (zero or negative = ground, positive = jump) - // param2 = chance to use tech (value is param3 + 0.6, clamped to [0, - // 1]; TODO: it's not clear when exactly the decision points are) - // param3 = chance to jump when more than 150 units away (value is - // param2 + 0.3, clamped to [0, 1]) + // param2 = chance to use tech (value is param3 + 0.6, clamped to [0, 1]; TODO: it's not clear when exactly the + // decision points are) + // param3 = chance to jump when more than 150 units away (value is param2 + 0.3, clamped to [0, 1]) // param6 = if >= 1, always rare {0x0040, F_V0_V4, 0x00000000001B0004, "TObjEneMoja"}, // Rappy. Params: - // param1 = initial location (zero or negative = ground, positive = sky; - // ignored if wave_number is > 0 in which case it's always sky) - // param6 = rare flag (on v1-v3, rappy is rare if param6 != 0; on v4, - // rappy is rare if (param6 & 1) != 0) + // param1 = initial location (zero or negative = ground, positive = sky; ignored if wave_number is > 0 in which + // case it's always sky) + // param6 = rare flag (on v1-v3, rappy is rare if param6 != 0; on v4, rappy is rare if (param6 & 1) != 0) // param7 = TODO // Exactly which rappy is constructed depends on param6 (or the random // rare check) and the current season event: @@ -3047,48 +2799,40 @@ static const vector dat_enemy_definitions({ // Monest (and Mothmants). Params: // param2 = number of Mothmants to expel at start (clamped to [0, 6]) - // param3 = total Mothmants (clamped to [0, min(30, num_children)] - // where num_children comes from the EnemySetEntry; if this is less - // than param2, then param2 will take precedence but no further - // Mothmants will emerge after the first group) - // Note: In map_forest01_02e.dat in the vanilla map files there is a - // Monest that has param1 = 3 and param2 = 10. This looks like just an - // off-by-one error on Sega's part where they accidentally shifted the - // parameters down by one place. As described above, this Monest expels - // 6 Mothmants immediately, then no more after those 6 are killed. + // param3 = total Mothmants (clamped to [0, min(30, num_children)] where num_children comes from the + // EnemySetEntry; if this is less than param2, then param2 will take precedence but no further Mothmants will + // emerge after the first group) + // Note: In map_forest01_02e.dat in the vanilla map files there is a Monest that has param1 = 3 and param2 = 10. + // This looks like just an off-by-one error on Sega's part where they accidentally shifted the parameters down by + // one place. As described above, this Monest expels 6 Mothmants immediately, then none after those 6 are killed. {0x0042, F_V0_V4, 0x0000000000180006, "TObjEneBm3FlyNest"}, // Savage Wolf or Barbarous Wolf. Params: - // param1 = group number (when a Barbarous Wolf dies, all wolves with - // the same group number howl and trigger their buffs or weaknesses) - // param2 = if less than 1, this is a Savage Wolf; otherwise it's a - // Barbarous Wolf + // param1 = group number (when a Barbarous Wolf dies, all wolves with the same group number howl and trigger + // their buffs or weaknesses) + // param2 = if less than 1, this is a Savage Wolf; otherwise it's a Barbarous Wolf {0x0043, F_V0_V4, 0x0000000000600006, "TObjEneBm5Wolf"}, // Booma, Gobooma, or Gigobooma. Params: // param1 = TODO (fraction of max HP; see TObjEnemyV8048ee80_v5A) - // param2 = idle walk radius (when there's no target, it will walk - // around its spawn location within this radius; if this is zero, it - // stands still instead) + // param2 = idle walk radius (when there's no target, it will walk around its spawn location within this radius; + // if this is zero, it stands still instead) // param6 = type (0 = Booma, 1 = Gobooma, 2 = Gigobooma) - // param7 = group ID (if nonzero, it looks like this is used to cause - // groups of enemies in the same room to band together and all attack - // the same player, chosen by the highest-ranking enemy (by param6) in - // the group; TODO: this explanation is unverified and param7 was never - // used by Sega; see client code at 3OE1:800F6F3C) + // param7 = group ID (if nonzero, it looks like this is used to cause groups of enemies in the same room to band + // together and all attack the same player, chosen by the highest-ranking enemy (by param6) in the group; TODO: + // this explanation is unverified and param7 was never used by Sega; see client code at 3OE1:800F6F3C) {0x0044, F_V0_V4, 0x0000000000000006, "TObjEneBeast"}, // Grass Assassin. Params: // param1 = TODO - // param2 = TODO (some state is set based on whether this is <= 0 or - // not, but the value is also used directly in some places) + // param2 = TODO (some state is set based on whether this is <= 0 or not, but the value is also used directly in + // some places) // param3 = TODO (see TObjGrass_update_case8) // param4 = TODO (see TObjGrass_update_case8) {0x0060, F_V0_V4, 0x00000000001B0018, "TObjGrass"}, - // Poison Lily or Del Lily. Del Lily is constructed if the current area - // is 0x23 (Control Tower); otherwise, Poison Lily is constructed. There - // appear to be no parameters. + // Poison Lily or Del Lily. Del Lily is constructed if the current area is 0x23 (Control Tower); otherwise, Poison + // Lily is constructed. There appear to be no parameters. {0x0061, F_V0_V4, 0x0000000800180038, "TObjEneRe2Flower"}, // Nano Dragon. Params: @@ -3097,28 +2841,24 @@ static const vector dat_enemy_definitions({ // param7 = TODO (set in init) {0x0062, F_V0_V4, 0x0000000000000038, "TObjEneNanoDrago"}, - // Evil Shark, Pal Shark, or Guil Shark. Same params as 0x0044 - // (TObjEneBeast), except: + // Evil Shark, Pal Shark, or Guil Shark. Same params as 0x0044 (TObjEneBeast), except: // param6 = type (0 = Evil Shark, 1 = Pal Shark, 2 = Guil Shark) {0x0063, F_V0_V4, 0x0000000000030038, "TObjEneShark"}, // Pofuilly Slime. num_children is clamped to [0, 4]. Params: - // param7 = rare flag (if the lowest bit is set, this is a Pouilly - // Slime instead; on BB, this is ignored) + // param7 = rare flag (if the lowest bit is set, this is a Pouilly Slime instead; on BB, this is ignored) {0x0064, F_V0_V4, 0x0000000000000030, "TObjEneSlime"}, // Pan Arms (Hidoom + Migium). There appear to be no parameters. {0x0065, F_V0_V4, 0x0000000000600028, "TObjEnePanarms"}, // Gillchic or Dubchic. Params: - // param1 = rapid fire count (number of lasers fired before moving - // again; if this is 0, the default of 2 is used) + // param1 = rapid fire count (number of lasers fired before moving again; if this is 0, the default of 2 is used) // param6 = type (0 = Dubchic, 1 = Gillchic) // param7 = TODO {0x0080, F_V0_V4, 0x00000000006000C0, "TObjEneDubchik"}, - // Garanz. There appear to be no parameters. - // TODO: There is some behavior difference if wave_number is 0 vs. any + // Garanz. There appear to be no parameters. TODO: There is some behavior difference if wave_number is 0 vs. any // other value. Figure out what exactly this does. {0x0081, F_V0_V4, 0x00000000002000C0, "TObjEneGyaranzo"}, @@ -3129,23 +2869,19 @@ static const vector dat_enemy_definitions({ {0x0082, F_V0_V4, 0x00000000000300C0, "TObjEneMe3ShinowaReal"}, // Canadine. Params: - // param1 = behavior (0 = in fighter, 1 = out fighter; this controls - // whether the Canadine will use its direct attack or stay high off - // the ground instead) + // param1 = behavior (0 = in fighter, 1 = out fighter; this controls whether the Canadine will use its direct + // attack or stay high off the ground instead) {0x0083, F_V0_V4, 0x00000000000000C0, "TObjEneMe1Canadin"}, - // Canane. There appear to be no parameters. There are always 8 followers - // arranged in a ring around the Canane. + // Canane. There appear to be no parameters. There are always 8 followers arranged in a ring around the Canane. {0x0084, F_V0_V4, 0x00000000000000C0, "TObjEneMe1CanadinLeader"}, - // Dubwitch. Destroying a Dubwitch destroys all Dubchics in the same - // room. There appear to be no parameters. + // Dubwitch. Destroying a Dubwitch destroys all Dubchics in the same room. There appear to be no parameters. {0x0085, F_V0_V4, 0x00000000006000C0, "TOCtrlDubchik"}, // Delsaber. Params: // param1 = jump distance delta (value used is param1 + 100) - // param2 = prejudice flag (these values directly correspond to the - // bits in PlayerVisualConfig::class_flags; see below for details): + // param2 = prejudice flag (these correspond to the bits in PlayerVisualConfig::class_flags): // 0 = males // 1 = females // 2 = humans @@ -3155,25 +2891,22 @@ static const vector dat_enemy_definitions({ // 6 = rangers // 7 = forces // 8 = no prejudice - // If any player is within 30 units of a Delsaber, it will target that - // player. Otherwise, the Delsaber will target the nearest player that - // matches its prejudice flag; if no player matches this flag, it will - // target the nearest player. + // If any player is within 30 units of a Delsaber, it will target that player. Otherwise, the Delsaber will target + // the nearest player that matches its prejudice flag; if no player matches, it will target the nearest player. {0x00A0, F_V0_V4, 0x0000000000630300, "TObjEneSaver"}, // Chaos Sorceror. There appear to be no parameters. {0x00A1, F_V0_V4, 0x0000000000400500, "TObjEneRe4Sorcerer"}, // Dark Gunner. Params: - // param1 = group number (there should be between 1 and 16 Dark Gunners - // and one control enemy with the same group number in the same room) + // param1 = group number (there should be between 1 and 16 Dark Gunners and one control enemy with the same group + // number in the same room) // param2 = TODO (number within group? possibly unused?) // param7 = TODO {0x00A2, F_V0_V4, 0x0000000000000600, "TObjEneDarkGunner"}, - // Dark Gunner control enemy. This enemy doesn't actually exist in-game; - // it only has logic for choosing a Dark Gunner from its group to be the - // leader, and then changing this leader periodically. Params: + // Dark Gunner control enemy. This enemy doesn't actually exist in-game; it only has logic for choosing a Dark + // Gunner from its group to be the leader, and then changing this leader periodically. Params: // param1 = group number (see above) {0x00A3, F_V0_V4, 0x0000000000000600, "TObjEneDarkGunCenter"}, @@ -3183,8 +2916,7 @@ static const vector dat_enemy_definitions({ // Dark Belra. There appear to be no parameters. {0x00A5, F_V0_V4, 0x0000000000180500, "TObjEneRe7Berura"}, - // Dimenian / La Dimenian / So Dimenian. Same parameters as 0x0044 - // (TObjEneBeast), except: + // Dimenian / La Dimenian / So Dimenian. Same parameters as 0x0044 (TObjEneBeast), except: // param6 = type (0 = Dimenian, 1 = La Dimenian, 2 = So Dimenian) {0x00A6, F_V0_V4, 0x0000000000180700, "TObjEneDimedian"}, @@ -3199,10 +2931,8 @@ static const vector dat_enemy_definitions({ {0x00C0, F_V3_V4, 0x0000000040000000, "TBoss5Gryphon"}, // Gal Gryphon {0x00C1, F_V0_V4, 0x0000000000001000, "TBoss2DeRolLe"}, // De Rol Le - // Vol Opt and various pieces thereof. Generally only TBoss3Volopt and - // TBoss3VoloptP02 should be specified in map files; the other enemies - // are automatically created by TBoss3Volopt. None of these take any - // parameters. + // Vol Opt and various pieces thereof. Generally only TBoss3Volopt and TBoss3VoloptP02 should be specified in map + // files; the other enemies are automatically created by TBoss3Volopt. None of these take any parameters. {0x00C2, F_V0_V4, 0x0000000000002000, "TBoss3Volopt"}, // Main control object {0x00C3, F_V0_V4, 0x0000000000002000, "TBoss3VoloptP01"}, // Phase 1 (x6; one for each big monitor) {0x00C4, F_V0_V4, 0x0000000000002000, "TBoss3VoloptCore"}, // Core @@ -3225,71 +2955,56 @@ static const vector dat_enemy_definitions({ // param2 = chance to enable stealth (value used is param2 + 0.3) // param3 = chance to cast technique (value used is param3 + 0.4) // param4 = chance to teleport (value used is param4 + 0.5) - // param5 = chance to disable stealth (value used is param5 + 0.1; - // applies when hit, but (TODO) also some other events) + // param5 = chance to disable stealth (value used is param5 + 0.1; applies when hit, but (TODO) also some other + // events) // param6 = type: // zero or negative = Sinow Berill // positive = Sinow Spigell - // param2, param3, and param4 are evaluated in that order after the Sinow - // jumps back. That is, the game first generates a random float between 0 - // and 1, and compares it to param2 to decide whether to enable stealth. - // If it does, the other params are ignored. If it doesn't, the game then - // checks param3 in the same manner to determine whether to cast a tech; - // if that doesn't happen either, the game checks param4 to determine - // whether to teleport. If none of those happen, the Sinow just walks - // forward again and attacks. + // param2, param3, and param4 are evaluated in that order after the Sinow jumps back. That is, the game first + // generates a random float between 0 and 1, and compares it to param2 to decide whether to enable stealth. If it + // does, the other params are ignored. If it doesn't, the game then checks param3 in the same manner to determine + // whether to cast a tech; if that doesn't happen either, the game checks param4 to determine whether to teleport. + // If none of those happen, the Sinow just walks forward again and attacks. {0x00D4, F_V3_V4, 0x000000000F800000, "TObjEneMe3StelthReal"}, // Merillia / Meriltas. Params: - // param1 = chance to run away after being hit (value used is param1 - - // 0.2, clamped below to 0) - // param3 = chance to do poison attack after being hit (value used is - // param3 - 0.2, clamped below to 0) + // param1 = chance to run away after being hit (value used is param1 - 0.2, clamped below to 0) + // param3 = chance to do poison attack after being hit (value used is param3 - 0.2, clamped below to 0) // param4 = distance to run away (value used is param4 + 300) - // param5 = wakeup radius delta (value used is param5 + 100, clamped - // below to 15; enemy will wake up when any player is nearby) + // param5 = wakeup radius delta (value used is param5 + 100, clamped below to 15; enemy will wake up when any + // player is nearby) // param6 = type (0 = Merillia, 1 = Meriltas) {0x00D5, F_V3_V4, 0x000000040F800000, "TObjEneMerillLia"}, // Mericarol / Mericus / Merikle / Mericarand. Params: - // param1 = chance of doing run attack after being hit when HP is less - // than half of max (value used is param1 + 0.5) - // param2 = speed during run attack (units per frame; value used is - // param2 + 3, clamped below to 1) - // param3 = chance of doing spit attack when player is nearby (actual - // probability is param3 + 0.1; if the check fails, it will do the - // slash attack instead) + // param1 = chance of run attack after being hit when HP is less than half of max (value used is param1 + 0.5) + // param2 = speed during run attack (units per frame; value used is param2 + 3, clamped below to 1) + // param3 = chance of doing spit attack when player is nearby (actual probability is param3 + 0.1; if the check + // fails, it will do the slash attack instead) // param6 = subtype: // 0 = Mericarol // 1 = Mericus // 2 = Merikle // anything else = Mericarand (see below) - // If this is a Mericarand, it is "randomly" chosen to be one of the - // three subtypes at construction time. On v1-v3, the client chooses - // randomly (but consistently, based on the entity ID) between Mericarol - // (80%), Mericus (10%) or Merikle (10%). On v4, if the entity ID isn't - // marked rare by the server, the Mericarand becomes a Mericarol; - // otherwise, it becomes a Mericus if its entity ID is even or a Merikle - // if it's odd. + // If this is a Mericarand, it is "randomly" chosen to be one of the three subtypes at construction time. On v1-v3, + // the client chooses randomly (but consistently, based on the entity ID) between Mericarol (80%), Mericus (10%) or + // Merikle (10%). On v4, if the entity ID isn't marked rare by the server, the Mericarand becomes a Mericarol; + // otherwise, it becomes a Mericus if its entity ID is even or a Merikle if it's odd. {0x00D6, F_V3_V4, 0x000000080F800000, "TObjEneBm9Mericarol"}, // Ul Gibbon / Zol Gibbon. Params: // param1 = group number // param2 = appear type (<1 = spot appear; >=1 = jump appear) - // param3 = chance of jumping forward or back at each decision point - // (value used is param3 + 0.4) - // param4 = chance of casting a tech when not near any player (value - // used is param4 + 0.3) - // param5 = chance of casting a tech immediately after jumping forward - // or back (value used is param5 + 0.3; does not apply after jumps - // that are attacks) + // param3 = chance of jumping forward or back at each decision point (value used is param3 + 0.4) + // param4 = chance of casting a tech when not near any player (value used is param4 + 0.3) + // param5 = chance of casting a tech immediately after jumping forward or back (value used is param5 + 0.3; does + // not apply after jumps that are attacks) // param6 = type (zero or negative = Ul Gibbon, positive = Zol Gibbon) {0x00D7, F_V3_V4, 0x000000040F800000, "TObjEneBm5GibonU"}, // Gibbles. Params: // param1 = jump distance delta (value used is param1 + 100) - // param2 = prejudice flag (see 0x00A0 (TObjEneSaver); the behavior - // here is exactly the same) + // param2 = prejudice flag (see 0x00A0 (TObjEneSaver); the behavior here is exactly the same) // param3 = chance to jump at each decision point (0-1) // param4 = chance to jump after being hit (0-1) {0x00D8, F_V3_V4, 0x000000080F800000, "TObjEneGibbles"}, @@ -3299,15 +3014,13 @@ static const vector dat_enemy_definitions({ // param2 = appear height (0 = low, 1 = high) // param3 = appear speed (value is param3 + 1, clamped below to 1) // param4 = needle speed (value is param4 + 6, clamped below to 0.01) - // Note: The client's debug strings say "APPEAR SPEED(+1.f Min:0.01f)" - // for param3 and "NEEDLE SPEED(+6.f Min:1.f)" for param4. The "Min:" - // parts of those strings are incorrect; the comments above are correct. + // Note: The client's debug strings say "APPEAR SPEED(+1.f Min:0.01f)" for param3 and "NEEDLE SPEED(+6.f Min:1.f)" + // for param4. The "Min:" parts of those strings are incorrect; the comments above are correct. {0x00D9, F_V3_V4, 0x000000040F800000, "TObjEneMe1Gee"}, // Gi Gue. Params: // param1 = TODO (only matters if >= 1 or not) - // param2 = TODO (only used if param1 >= 1; defaults to 50 if param2 < - // 1; maybe same as Nano Dragon's param2?) + // param2 = TODO (only used if param1 >= 1; defaults to 50 if param2 < 1; maybe same as Nano Dragon's param2?) // param3 = TODO (value is param3 + 150) // param4 = TODO (value is param4 + 0.5) // param5 = TODO (value is param5 + 0.5) @@ -3315,15 +3028,13 @@ static const vector dat_enemy_definitions({ {0x00DA, F_V3_V4, 0x000000080F800000, "TObjEneMe1GiGue"}, // Deldepth. Params: - // param1 = TODO (value is param1 + 0.6, clamped below to 0; seems to - // be unused?) + // param1 = TODO (value is param1 + 0.6, clamped below to 0; seems to be unused?) {0x00DB, F_V3_V4, 0x0000000030000000, "TObjEneDelDepth"}, // Delbiter. Params: // param1 = chance to howl (value is param1 + 0.3) // param2 = chance to cause confusion via howl (value is param2 + 0.3) - // param3 = maximum distance at which howl can cause confusion (value - // is param3 + 30, clamped below to 10) + // param3 = maximum distance at which howl can cause confusion (value is param3 + 30, clamped below to 10) // param4 = chance to fire laser (value is param4 + 0.3) // param5 = chance to charge (value is param5 + 0.05) // param6 = type (0 = stand, 1 = run) @@ -3338,32 +3049,26 @@ static const vector dat_enemy_definitions({ // Morfos. Params: // param1 = TODO (value is param1 + 0.28) // param2 = TODO (value is param2 + 20) - // param3 = TODO (value is param3 + 0.1; probability; used when current - // HP is less than half of max) - // param4 = TODO (value is param4 + 0.1; probability; used when current - // HP is less than half of max) + // param3 = TODO (value is param3 + 0.1; probability; used when current HP is less than half of max) + // param4 = TODO (value is param4 + 0.1; probability; used when current HP is less than half of max) // param6 = TODO {0x00DE, F_V3_V4, 0x0000000030000000, "TObjEneMorfos"}, // Recobox. Params: - // param1 = Recon floating height (value used for each Recon is 45 + - // rand(-2, 2) + param1) - // param2 = Recon target radius (distance from target; value used for - // each Recon is 50 + rand(-5, 5) + param2; param2 is clamped below - // to -30) - // param4 = maximum number of concurrently-active Recons (clamped to - // [0, min(6, num_children - 1)]) + // param1 = Recon floating height (value used for each Recon is 45 + rand(-2, 2) + param1) + // param2 = Recon target radius (distance from target; value used for each Recon is 50 + rand(-5, 5) + param2; + // param2 is clamped below to -30) + // param4 = maximum number of concurrently-active Recons (clamped to [0, min(6, num_children - 1)]) // param6 = type: // zero or negative = floor (Recons exit upward) // 1 = ceiling (Recons exit downward) // 2 or greater = wall (Recons exit horizontally) - // Note: The debug strings in TObjEneRecobox_v6A seem to imply that the - // total Recon count in the box is (param7 + 1); however, this is not - // true. The total Recon count in the box is actually (num_children - 1). + // Note: The debug strings in TObjEneRecobox_v6A seem to imply that the total Recon count in the box is (param7 + + // 1); however, this is not true. The total Recon count in the box is actually (num_children - 1). {0x00DF, F_V3_V4, 0x0000000C30000000, "TObjEneRecobox"}, - // Sinow Zoa / Sinow Zele. It appears to take the same params as - // TObjEneMe3StelthReal (Sinow Berill / Sinow Spigell), except (of course): + // Sinow Zoa / Sinow Zele. It appears to take the same params as TObjEneMe3StelthReal (Sinow Berill / Sinow + // Spigell), except (of course): // param6 = type: // zero or negative = Sinow Zoa // positive = Sinow Zele @@ -3371,8 +3076,8 @@ static const vector dat_enemy_definitions({ // Epsilon. Params: // param1 = TODO (value is param1 + 0.5, clamped below to 0) - // param2 = TODO (value is param2 + 512; it appears this was supposed - // to be clamped below to 0, but due to a copy/paste error it isn't) + // param2 = TODO (value is param2 + 512; it appears this was supposed to be clamped below to 0, but due to a + // copy/paste error it isn't) // param3 = TODO (value is (param3 + 20) * 5, clamped below to 150) // param4 = TODO (value is (param4 + 20) * 5, clamped below to 150) {0x00E0, F_V3_V4, 0x0000000800000000, "TObjEneEpsilonBody"}, @@ -3420,22 +3125,19 @@ static const vector dat_enemy_definitions({ // param5 = TODO (value is param5 + 0.05) // param6 = flags (bit field): // 0001 = always rare (Dorphon Eclair) - // TODO: The values above make it look like param1-5 are the same as for - // TObjEneDellBiter. Verify if this is the case. + // TODO: The values above make it look like param1-5 are the same as for TObjEneDellBiter. Verify if this is true. {0x0116, F_V4, 0x000041F000000000, "__DORPHON__"}, - // Goran / Pyro Goran / Goran Detonator. Same parameters as TObjEneBeast, - // but also: + // Goran / Pyro Goran / Goran Detonator. Same parameters as TObjEneBeast, but also: // param3 = TODO (see v58, v67) // param6 = type (0 = Goran, 1 = Pyro Goran, 2 = Goran Detonator) {0x0117, F_V4, 0x00004E0000000000, "__GORAN_FAMILY__"}, // Saint-Milion / Shambertin / Kondrieu. Params: - // param1 = TODO (see TObjEneV00b43ca0::set_params; seems it only matters - // if this is zero or not) + // param1 = TODO (see TObjEneV00b43ca0::set_params; seems it only matters if this is zero or not) // param6 = flags (bit field): - // 0001 = type (0 = Saint-Milion, 1 = Shambertin; ignored if enemy is - // set as rare by the server, in which case it's Kondrieu) + // 0001 = type (0 = Saint-Milion, 1 = Shambertin; ignored if enemy is set as rare by the server, in which case + // it's Kondrieu) {0x0119, F_V4, 0x0000100000000000, "__EPISODE_4_BOSS__"}, }); @@ -3465,8 +3167,7 @@ static string name_for_entity_type( } } - // When matching only by type or by (type, version), we can expect multiple - // matches + // When matching only by type or by (type, version), we can expect multiple matches if (version != Version::UNKNOWN) { string ret; for (auto [it, end_it] = its; it != end_it; it++) { @@ -3739,10 +3440,9 @@ void MapFile::RandomState::generate_shuffled_location_table( } const array MapFile::RAND_ENEMY_BASE_TYPES = { - 0x44, 0x43, 0x41, 0x42, 0x40, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x80, - 0x81, 0x82, 0x83, 0x84, 0x85, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, - 0xDE, 0xDF, 0xE0, 0xE0, 0xE1}; + 0x44, 0x43, 0x41, 0x42, 0x40, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0xA0, 0xA1, + 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE0, 0xE1}; MapFile::MapFile(std::shared_ptr data) { this->quest_data = data; @@ -4404,7 +4104,7 @@ string MapFile::disassemble(bool reassembly, Version version) const { return phosg::join(ret, "\n"); } -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Super map string SuperMap::Object::id_str() const { @@ -4417,8 +4117,7 @@ string SuperMap::Object::str() const { const auto& def = this->version(v); if (def.relative_object_index != 0xFFFF) { string args_str = def.set_entry->str(v); - ret += std::format( - " {}:[{:04X} => {}]", phosg::name_for_enum(v), def.relative_object_index, args_str); + ret += std::format(" {}:[{:04X} => {}]", phosg::name_for_enum(v), def.relative_object_index, args_str); } } ret += "]"; @@ -4465,11 +4164,7 @@ string SuperMap::Event::str() const { string action_stream_str = phosg::format_data_string(def.action_stream, def.action_stream_size); string args_str = def.set_entry->str(); ret += std::format( - " {}:[{:04X} => {}+{}]", - phosg::name_for_enum(v), - def.relative_event_index, - args_str, - action_stream_str); + " {}:[{:04X} => {}+{}]", phosg::name_for_enum(v), def.relative_event_index, args_str, action_stream_str); } } ret += "]"; @@ -4588,8 +4283,7 @@ shared_ptr SuperMap::add_enemy_and_children( auto& entities = this->version(version); - // TODO: It'd be nice to share some code between this function and - // link_enemy_version_and_children + // TODO: It'd be nice to share some code between this function and link_enemy_version_and_children // Create enemy auto ene = make_shared(); @@ -4604,10 +4298,9 @@ shared_ptr SuperMap::add_enemy_and_children( auto& ene_ver = ene->version(version); ene_ver.set_entry = set_entry; ene_ver.relative_enemy_index = entities.enemies.size(); - // If child_index > 0, then the head enemy was already created, so we need - // to subtract 1 from the set index because this new enemy should have the - // same set index as the head enemy, but the head enemy was already added - // to the enemy sets list. + // If child_index > 0, then the head enemy was already created, so we need to subtract 1 from the set index because + // this new enemy should have the same set index as the head enemy, but the head enemy was already added to the + // enemy sets list. ene_ver.relative_set_index = entities.enemy_sets.size() - (ene->child_index != 0); // Add to primary enemy lists @@ -4625,9 +4318,8 @@ shared_ptr SuperMap::add_enemy_and_children( return ene; }; - // The following logic was originally based on the public version of - // Tethealla, created by Sodaboy. I've augmented it with findings from my own - // research. + // The following logic was originally based on the public version of Tethealla, created by Sodaboy. I've augmented it + // with findings from my own research. EnemyType child_type = EnemyType::UNKNOWN; ssize_t default_num_children = 0; @@ -4740,8 +4432,7 @@ shared_ptr SuperMap::add_enemy_and_children( break; } case 0x0064: { // TObjEneSlime - // Unlike all other versions, BB doesn't have a way to force slimes to be - // rare via constructor args + // Unlike all other versions, BB doesn't have a way to force slimes to be rare via constructor args bool is_rare_v123 = (set_entry->param7 & 1); default_num_children = -1; // Skip adding children later (because we do it here) size_t num_children = set_entry->num_children ? set_entry->num_children.load() : 4; @@ -5072,10 +4763,9 @@ void SuperMap::link_enemy_version_and_children( ene_ver.set_entry = set_entry; ene_ver.relative_enemy_index = entities.enemies.size(); - // If child_index > 0, then the head enemy was already created, so we need - // to subtract 1 from the set index because this new enemy should have the - // same set index as the head enemy, but the head enemy was already added - // to the enemy sets list. + // If child_index > 0, then the head enemy was already created, so we need to subtract 1 from the set index because + // this new enemy should have the same set index as the head enemy, but the head enemy was already added to the + // enemy sets list. ene_ver.relative_set_index = entities.enemy_sets.size() - (ene->child_index != 0); // Add to primary enemy lists @@ -5187,11 +4877,10 @@ void SuperMap::link_event_version( entities.event_for_floor_and_event_id.emplace(k, ev); } -// This is a modified version of a simple dynamic programming edit distance -// algorithm. Conceptually, the previous map file's entries go down the left -// side of the matrix, and the current map file's entries go across the top. -// To save time, we run it once per floor, since we never expect objects on -// different floors in different versions to logically be the same object. +// This is a modified version of a simple dynamic programming edit distance algorithm. Conceptually, the previous map +// file's entries go down the left side of the matrix, and the current map file's entries go across the top. To save +// time, we run it once per floor, since we never expect objects on different floors in different versions to logically +// be the same object. enum class EditAction { STOP = 0, // Reverse path ends here (at end, this should only be at (0, 0)) @@ -5257,8 +4946,7 @@ vector compute_edit_path( Matrix mtx(curr_count + 1, prev_count + 1); - // Along the top and left edges, there is only one possible reverse path, so - // fill those in first + // Along the top and left edges, there is only one possible reverse path, so fill those in first for (size_t x = 1; x <= curr_count; x++) { auto& e = mtx.at(x, 0); e.cost = mtx.at(x - 1, 0).cost + get_add_cost(curr[x - 1]); @@ -5336,15 +5024,15 @@ vector> compute_prev_entities( for (auto action : edit_path) { switch (action) { case EditAction::ADD: - // This object doesn't match any object from the previous version + // This entity doesn't match any entity from the previous version ret.emplace_back(nullptr); break; case EditAction::DELETE: - // There is an object in the previous version that doesn't match any in this version; skip it + // There is an entity in the previous version that doesn't match any in this version; skip it prev_entities_offset++; break; case EditAction::EDIT: { - // The current object in this_sf matches the current object in prev_sf; link them together + // The current entity in this_sf matches the current entity in prev_sf; link them together ret.emplace_back(existing_prev_entities.at(prev_entities_offset)); prev_entities_offset++; break; @@ -5367,8 +5055,7 @@ static double object_set_edit_cost(const MapFile::ObjectSetEntry& prev, const Ma if (prev.base_type != current.base_type) { return 500.0; } - // Group or room changes are pretty bad, but small variances in position - // and params are tolerated + // Group or room changes are pretty bad, but small variances in position and params are tolerated return ( ((prev.group != current.group) * 50.0) + ((prev.room != current.room) * 50.0) + @@ -5388,13 +5075,11 @@ static double enemy_set_delete_cost(const MapFile::EnemySetEntry&) { return 100.0; } static double enemy_set_edit_cost(const MapFile::EnemySetEntry& prev, const MapFile::EnemySetEntry& current) { - // A change of type or num_children is not tolerated and should never be - // better than an add + delete + // A change of type or num_children is not tolerated and should never be better than an add + delete if ((prev.base_type != current.base_type) || (prev.num_children != current.num_children)) { return 500.0; } - // Room or wave_number changes are pretty bad, but small variances in - // position and params are tolerated + // Room or wave_number changes are pretty bad, but small variances in position and params are tolerated return ( ((prev.room != current.room) * 50.0) + ((prev.wave_number != current.wave_number) * 50.0) + @@ -5506,8 +5191,7 @@ void SuperMap::add_map_file(Version this_v, shared_ptr this_map_f const auto& this_sf = this_map_file->floor(floor); if (!prev_map_file || !prev_map_file->floor(floor).object_sets) { - // All objects were added in this version, or there was no previous - // version. Add all the objects as new objects. + // All objects were added in this version, or there was no previous version. Add all the objects as new objects. for (size_t z = 0; z < this_sf.object_set_count; z++) { this->add_object(this_v, floor, this_sf.object_sets + z); } @@ -5779,8 +5463,7 @@ void SuperMap::verify() const { } if (ene->super_set_id != super_set_id) { throw logic_error(std::format( - "enemy super_set_id is incorrect; expected S-{:03X}, received S-{:03X}", - super_set_id, ene->super_set_id)); + "enemy super_set_id is incorrect; expected S-{:03X}, received S-{:03X}", super_set_id, ene->super_set_id)); } } if (super_set_id != this->enemy_sets.size() - 1) { @@ -6006,7 +5689,7 @@ void SuperMap::print(FILE* stream) const { } } -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Map state MapState::RareEnemyRates::RareEnemyRates(uint32_t enemy_rate, uint32_t mericarand_rate, uint32_t boss_rate) @@ -6323,29 +6006,25 @@ void MapState::index_super_map(const FloorConfig& fc, shared_ptrrandom_seed + 0x1000 + enemy_index; float det; try { det = det_cache.at(seed); } catch (const out_of_range&) { - // TODO: We only need the first value from this crypt, so it's - // unfortunate that we have to initialize the entire thing. Find - // a way to make this faster. + // TODO: We only need the first value from this crypt, so it's unfortunate that we have to initialize the + // entire thing. Find a way to make this faster. PSOV2Encryption crypt(seed); det = (static_cast((crypt.next() >> 16) & 0xFFFF) / 65536.0f); det_cache.emplace(seed, det); } if (type == EnemyType::MERICARAND) { - // On v3, Mericarols that have param6 > 2 are randomized to be - // Mericus, Merikle, or Mericarol, but the former two are not - // considered rare. (We use rare_flags anyway to distinguish them - // from Mericarol.) + // On v3, Mericarols that have param6 > 2 are randomized to be Mericus, Merikle, or Mericarol, but the + // former two are not considered rare. (We use rare_flags anyway to distinguish them from Mericarol.) if (det > 0.9) { // Merikle ene_st->set_rare(v); ene_st->set_mericarand_variant_flag(v); @@ -6383,10 +6062,8 @@ void MapState::index_super_map(const FloorConfig& fc, shared_ptrdynamic_obj_base_k_id = this->object_states.size(); - // Compute the maximum object ID for each version. We can't just use the last - // object because that object may not exist on all versions, and we can't - // just look at the last floor, because that floor may be empty on some - // versions. + // Compute the maximum object ID for each version. We can't just use the last object because that object may not + // exist on all versions, and we can't just look at the last floor, because that floor may be empty on some versions. this->dynamic_obj_base_index_for_version.fill(0); for (const auto& fc : this->floor_config_entries) { for (Version v : ALL_NON_PATCH_VERSIONS) { @@ -6631,8 +6308,7 @@ void MapState::import_object_states_from_sync( const auto& entities = fc.super_map->version(from_version); size_t fc_end_object_index = base_indexes.base_object_index + entities.objects.size(); if (fc_end_object_index > entry_count) { - // DC NTE sometimes has fewer objects than the map, but only by 1. - // TODO: Figure out why this happens. + // DC NTE sometimes has fewer objects than the map, but only by 1. TODO: Figure out why this happens. if (from_version == Version::DC_NTE) { fc_end_object_index = entry_count; } else { @@ -6724,8 +6400,7 @@ void MapState::import_flag_states_from_sync( const auto& entities = fc.super_map->version(from_version); size_t fc_end_object_index = base_indexes.base_object_index + entities.objects.size(); if (fc_end_object_index > object_set_flags_count) { - // DC NTE sometimes has fewer objects than the map, but only by 1. - // TODO: Figure out why this happens. + // DC NTE sometimes has fewer objects than the map, but only by 1. TODO: Figure out why this happens. if (from_version == Version::DC_NTE) { fc_end_object_index = object_set_flags_count; } else { diff --git a/src/Map.hh b/src/Map.hh index b7a23845..22b83cc7 100644 --- a/src/Map.hh +++ b/src/Map.hh @@ -16,7 +16,7 @@ #include "StaticGameData.hh" #include "Text.hh" -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Game structures (used in 6x6B/6x6C/6x6E handlers, and here) struct SyncEnemyStateEntry { @@ -34,7 +34,7 @@ struct SyncObjectStateEntry { le_uint16_t item_drop_id = 0; } __packed_ws__(SyncObjectStateEntry, 0x04); -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Set data table (variations index) struct Variations { @@ -98,8 +98,7 @@ private: template void load_table_t(const std::string& data); - // Indexes are [floor][variation1][variation2] - // floor is cumulative per episode, so Ep2 starts at floor=18. + // Indexes are [floor][variation1][variation2]; floor is cumulative per episode, so Ep2 starts at floor=18. std::vector>> entries; }; @@ -131,12 +130,10 @@ private: static const std::array>, 0x12> NAMES; }; -//////////////////////////////////////////////////////////////////////////////// -// Map (DAT) file parser. This class is responsible for parsing individual -// quest DAT files, or up to three individual free-play DAT files (object sets, -// enemy sets, and events, each of which are optional). In the free-play case, -// the MapFile represents entities for a single floor; in the quest case, it -// represents the lists for all floors. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Map (DAT) file parser. This class is responsible for parsing individual quest DAT files, or up to three individual +// free-play DAT files (object sets, enemy sets, and events, each of which are optional). In the free-play case, the +// MapFile represents entities for a single floor; in the quest case, it represents the lists for all floors. class MapFile : public std::enable_shared_from_this { public: @@ -171,14 +168,12 @@ public: /* 0A */ le_uint16_t group = 0; /* 0C */ le_uint16_t room = 0; /* 0E */ le_uint16_t unknown_a3 = 0; - // The position is relative to the room in which the object is placed; to - // get the actual world position, the object's position must be rotated - // around the room's origin by the room's angles, then translated by the - // room's offset. The room's angle and offset can be found in the area's - // n.rel file. + // The position is relative to the room in which the object is placed; to get the actual world position, the + // object's position must be rotated around the room's origin by the room's angles, then translated by the room's + // offset. The room's angle and offset can be found in the area's n.rel file. /* 10 */ VectorXYZF pos; - // Angles are specified as 16-bit integers, where 0 is no rotation around - // the axis and FFFF is almost a complete counterclockwise rotation. + // Angles are specified as 16-bit integers, where 0 is no rotation around the axis and FFFF is almost a complete + // counterclockwise rotation. /* 1C */ VectorXYZI angle; // See notes in dat_object_definitions in Map.cc for how these are used /* 28 */ le_float param1 = 0.0f; @@ -198,7 +193,7 @@ public: /* 00 */ le_uint16_t base_type = 0; /* 02 */ le_uint16_t set_flags = 0; // Used by PSO at runtime, unused in DAT file /* 04 */ le_uint16_t index = 0; // Used by PSO at runtime, unused in DAT file - /* 06 */ le_uint16_t num_children = 0; // If == 0, use the default child count from the constructor table (which is often also 0) + /* 06 */ le_uint16_t num_children = 0; // If == 0, use the default child count from the constructor table /* 08 */ le_uint16_t floor = 0; /* 0A */ le_uint16_t entity_id = 0; // == index + 0x1000; used by PSO at runtime, unused in DAT file /* 0C */ le_uint16_t room = 0; @@ -223,10 +218,9 @@ public: } __packed_ws__(EnemySetEntry, 0x48); struct EventsSectionHeader { // Section type 3 (EVENTS) - // The events section has three zones: the header (this structure), the - // event entries, and the action stream. The header specifies where to find - // each one in the section, and how many entries there are. The offsets - // here are relative to the beginning of the header. + // The events section has three zones: the header (this structure), the event entries, and the action stream. The + // header specifies where to find each one in the section, and how many entries there are. The offsets here are + // relative to the beginning of the header. /* 00 */ le_uint32_t action_stream_offset; /* 04 */ le_uint32_t entries_offset; /* 08 */ le_uint32_t entry_count; @@ -239,62 +233,50 @@ public: } __packed_ws__(EventsSectionHeader, 0x10); struct Event1Entry { // Section type 3 (EVENTS) if format == 0 - // A wave event consists of an event (this struct) and an action stream, - // which is a short script that runs when all enemies in the wave are - // killed. Generally, events work like this: - // 1. The event is triggered (e.g. via a quest script or trigger object). - // This sets flag 0004 on the wave event. - // 2. The client constructs a TSetEvtDestroy object, which despite its - // name, is also responsible for constructing enemies. This sets flag - // 0002 on the wave event. This object waits for the delay specified - // in this structure (in frames), then constructs the wave's enemies. + // A wave event consists of an event (this struct) and an action stream, which is a short script that runs when all + // enemies in the wave are killed. Generally, events work like this: + // 1. The event is triggered (e.g. via a quest script or trigger object). This sets flag 0004 on the wave event. + // 2. The client constructs a TSetEvtDestroy object, which despite its name, is also responsible for constructing + // enemies. This sets flag 0002 on the wave event. This object waits for the delay specified in this structure + // (in frames), then constructs the wave's enemies. // 3. The player kills all the enemies. // 4. The TSetEvtDestroy object sets flag 0010 on the event. - // 5. The TSetEvtDestroy object sets flag 0008 on the event and runs the - // post-wave actions. (This happens one frame after the above.) See - // the implementation of MapFile::disassemble_action_stream for - // details on the format of post-wave actions. It then clears flag - // 0004 (but not 0002). + // 5. The TSetEvtDestroy object sets flag 0008 on the event and runs the post-wave actions. (This happens one + // frame after the above.) See the implementation of MapFile::disassemble_action_stream for details on the + // format of post-wave actions. It then clears flag 0004 (but not 0002). - // The event ID identifies this event on the current floor. It is not - // required that all wave events have unique IDs; if multiple events have - // the same ID, they will all trigger at the same time when any one of them - // is triggered (since wave events can only be triggered by ID). + // The event ID identifies this event on the current floor. It is not required that all wave events have unique + // IDs; if multiple events have the same ID, they will all trigger at the same time when any one of them is + // triggered (since wave events can only be triggered by ID). /* 00 */ le_uint32_t event_id = 0; - // The flags field specifies the state of the event. This field is synced - // to a joining player as part of the 6x6E command during the game loading - // sequence. Known bits: - // 0002 = wave object constructor has been called (this flag is not - // synced via 6x6E) + // The flags field specifies the state of the event. This field is synced to a joining player as part of the 6x6E + // command during the game loading sequence. Known bits: + // 0002 = wave object constructor has been called (this flag is not synced via 6x6E) // 0004 = is active (has been triggered) // 0008 = post-wave actions have been run // 0010 = all enemies killed /* 04 */ le_uint16_t flags = 0; // Used by PSO at runtime, unused in file - // It seems Sega originally wanted to support multiple types of events, and - // the event_type field controls which constructor is called when the event - // is triggered by a 6x67 command. It seems they never actually used this - // though; there are only two valid values: 0 makes the event do nothing - // (no object is constructed at all) and 1 uses the normal control object - // (TSetEvtDestroy). There is no bounds check here, so any other value - // causes undefined behavior. + // It seems Sega originally wanted to support multiple types of events, and the event_type field controls which + // constructor is called when the event is triggered by a 6x67 command. It seems they never actually used this + // though; there are only two valid values: 0 makes the event do nothing (no object is constructed at all) and 1 + // uses the normal control object described above (TSetEvtDestroy). There is no bounds check here, so any other + // value causes undefined behavior. /* 06 */ le_uint16_t event_type = 1; - // The room and wave_number fields specify which enemies should be - // constructed when this event triggers. All enemies whose room and - // wave_number fields match these two fields are constructed at the same - // time when the event triggers (or after the delay below). + // The room and wave_number fields specify which enemies should be constructed when this event triggers. All + // enemies whose room and wave_number fields match these two fields are constructed at the same time when the event + // triggers (or after the delay below). /* 08 */ le_uint16_t room = 0; /* 0A */ le_uint16_t wave_number = 0; - // The delay field specified how long (in frames) to wait after the event's - // trigger time before constructing all the enemies. + // The delay field specified how long (in frames) to wait after the event's trigger time before constructing all + // the enemies. /* 0C */ le_uint32_t delay = 0; - // This field specifies where in the action stream data to start running - // commands for this event, when all enemies are defeated. This is relative - // to the beginning of the action stream, not the events section header. + // This field specifies where in the action stream data to start running commands for this event, when all enemies + // are defeated. This is relative to the beginning of the action stream, not the events section header. /* 10 */ le_uint32_t action_stream_offset = 0; /* 14 */ @@ -355,8 +337,8 @@ public: } __packed_ws__(RandomEnemyDefinitionsHeader, 0x10); struct RandomEnemyDefinition { // Section type 5 (RANDOM_ENEMY_DEFINITIONS) - // All fields through entry_num map to the corresponding fields in - // EnemySetEntry. Note that the order of param6 and param7 is switched! + // All fields through entry_num map to the corresponding fields in EnemySetEntry. Note that the order of param6 and + // param7 is switched! /* 00 */ le_float param1; /* 04 */ le_float param2; /* 08 */ le_float param3; @@ -466,9 +448,8 @@ public: return this->has_any_random_sections; } - // If the map file has no random sections, does nothing and returns a - // shared_ptr to this. If it has any random sections, returns a new map with - // all non-random sections copied verbatim, and random sections replaced with + // If the map file has no random sections, does nothing and returns a shared_ptr to this. If it has any random + // sections, returns a new map with all non-random sections copied verbatim, and random sections replaced with // non-random sections according to the challenge mode generation algorithm. std::shared_ptr materialize_random_sections(uint32_t random_seed); std::shared_ptr materialize_random_sections(uint32_t random_seed) const; @@ -508,19 +489,15 @@ protected: int64_t generated_with_random_seed = -1; }; -//////////////////////////////////////////////////////////////////////////////// -// Super map. This class is responsible for collecting entity lists across PSO -// versions and diffing them to link together entities that don't line up -// across versions. This class also generates enemy lists from enemy set lists, -// which MapFile doesn't do. Like MapFile, a single SuperMap is either -// responsible for all entities on all floors in a quest, or all entities on a -// single floor in free play. Each entity is assigned a "super ID", which -// uniquely identifies the entity on all PSO versions. (These are the IDs which -// newserv formats as K-XXX, E-XXX, and W-XXX, though they are offset as needed -// for floors beyond the first.) -// There must not be any random enemy sections in any MapFile passed to -// SuperMap; to resolve them, materialize_random_sections must be called on all -// MapFiles first. This generally only is of concern in Challenge mode. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Super map. This class is responsible for collecting entity lists across PSO versions and diffing them to link +// together entities that don't line up across versions. This class also generates enemy lists from enemy set lists, +// which MapFile doesn't do. Like MapFile, a single SuperMap is either responsible for all entities on all floors in a +// quest, or all entities on a single floor in free play. Each entity is assigned a "super ID", which uniquely +// identifies the entity on all PSO versions. (These are the IDs which newserv formats as K-XXX, E-XXX, and W-XXX, +// though they are offset as needed for floors beyond the first.) +// There must not be any random enemy sections in any MapFile passed to SuperMap; to resolve them, +// materialize_random_sections must be called on all MapFiles first. This generally only is needed in Challenge mode. class SuperMap { public: @@ -714,11 +691,10 @@ protected: void add_map_file(Version v, std::shared_ptr this_map_file); }; -//////////////////////////////////////////////////////////////////////////////// -// Map state. This class is responsible for keeping track of the in-game state -// of objects, enemies, and events. This is the only class that's constructed -// for every game; the others are essentially immutable data once loaded, which -// this class refers to. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Map state. This class is responsible for keeping track of the in-game state of objects, enemies, and events. This is +// the only class that's constructed for every game; the others are essentially immutable data once loaded, and this +// class refers to them. class MapState { public: @@ -751,12 +727,10 @@ public: static const std::shared_ptr DEFAULT_RARE_ENEMIES; struct ObjectState { - // WARNING: super_obj CAN BE NULL! This is not the case for enemies and - // events; their super entities are never null. In the case of objects, - // dynamic objects like player-set traps have object IDs past the end of - // the map's object list, and when queried, the MapState will return a - // temporary ObjectState with a null super_obj. (In these cases, only k_id - // is needed for correctness.) + // WARNING: super_obj CAN BE NULL! This is not the case for enemies and events; their super entities are never + // null. In the case of objects, dynamic objects like player-set traps have object IDs past the end of the map's + // object list, and when queried, the MapState will return a temporary ObjectState with a null super_obj. (In these + // cases, only k_id is needed for correctness.) std::shared_ptr super_obj; size_t k_id = 0; uint16_t game_flags = 0; @@ -992,8 +966,7 @@ public: inline const FloorConfig& floor_config(uint8_t floor) const { return this->floor_config_entries[std::min(floor, this->floor_config_entries.size() - 1)]; } - // Resets states of all entities to their initial values. Used when - // restarting battles/challenges. + // Resets states of all entities to their initial values. Used when restarting battles/challenges. void reset(); inline Range iter_object_states(Version version) {