Skip to content

Attacks: the attack data decides on every map, rotations, map variants, one way to name maps - #135

Merged
Mosch0512 merged 30 commits into
mainfrom
feat/monster-attacks
Oct 30, 2026
Merged

Mosch0512 merged 30 commits into
mainfrom
feat/monster-attacks

Conversation

@Mosch0512

@Mosch0512 Mosch0512 commented Oct 29, 2026 •

Copy link
Copy Markdown
Owner

The second of the five PRs that finish the monster work (design, "Pull requests and phases"; the first was sven-n#882): a monster's attack data now decides its attack animation on every map, otherwise can be a rotation or the generic pattern, and a monster can attack differently on some maps through a map variant. Data names maps one way, by the numbers the server sends and the stages of Devil Square (which OpenMU now sends, Mosch0512/OpenMU#7), with one map picker in the editor. Monster Attacks can play what it edits in Monster Preview, which now plays the models' sound events too.

Commits

  1. docs(monsters): the answers to Q-MN64–Q-MN69 — data on every map (Q-MN64), map variants of attacks (Q-MN65, D62), the client keeps the server's map number (Q-MN66), one way to name maps (Q-MN67, D67), a variant's attacks replace the monster's (Q-MN68), rotations count in turn (Q-MN69); the content roadmap gets "maps as data".
  2. otherwise plays a rotation or the generic pattern — "otherwise": ["attack1", "attack3"] plays in turn, counted per monster from its creation (CHARACTER::AttackRotation); "otherwise": "generic" plays today's pattern exactly (its code moved into NextGenericAttack, which SetPlayerAttack and SetPlayerMagic call as before). A rotation cannot count by SwordCount: SetPlayerAttack adds 1 to it on every attack and the pattern 1 more, so lists would play out of order. Monster Attacks: an animation, a rotation, the generic pattern or a draw.
  3. fix(maps): GetMapName names the map it is asked for — it asked whether the hero is in the Balgass barracks, the refuge or Illusion Temple: while the hero was in the barracks, a party member's map and the portal and revive maps were called "Balgass' Barrack".
  4. the client keeps the server's map number — LoadWorld turns the server's map 32 (Devil Square 5–7) into world 9 and forgot 32; GetServerMap keeps it. GetFilesFolder is the one place that says which Data/World<n> folder a map loads (two copies before; same result for every map).
  5. the model list's world lists become map lists — Models.json's worldTextureFolders, parts' worlds and soundEventWorlds become mapTextureFolders, maps and soundEventMaps, compared with the server map. No list names 9 or 32, so the game plays the same; the file keeps format version 1 (the renamed keys exist only in the copy that ships).
  6. one map picker for the tools — the maps a server sends, each with its server number and world folder; the rounds of an event under one name (Devil Square 1–4 and 5–7, Blood Castle 1–8, Chaos Castle 1–7, Kalima 1–7, Illusion Temple 1–6, Doppelganger 1–4, Empire Guardian 1–4, Karutan 1–2). Monster Model's sound events pick their maps in it instead of typing numbers.
  7. map variants of a monster's attacks — "mapVariants": [{"maps": [32], "attacks": {...}}]: on its maps a variant's attacks replace the monster's. A map in two variants is fatal, a variant without attacks a warning. Monster Attacks gets a Map row (All maps, each variant, Add a map variant; Plays on in the map picker; Remove the map variant).
  8. the attack data decides on every map — the handlers that only played attacks for the numbers they listed go (Hellas, Hunting Ground, Aida, Crywolf/Devil Square, Kanturu 1st and 2nd, Balgass barracks, Illusion Temple, Swamp of Quiet, Bali's branch, the plain cases of Empire Guardian and Raklion, CheckMonsterSkill); a monster's attacks play on every map. Map code that is no choice of animation stays: the Battle Castle guards' attack state, Maya's scene, Selupan, the Empire Guardian bosses' rage, the traps' effects. Two numbers keep their map behaviour in data: Fire Golem 291 plays the generic pattern in Devil Square 5–7 (its boss wave there; the owner takes that as intended), Erkanne 507 plays nothing in Loren Market.
  9. docs(monsters): the answers to Q-MN70–Q-MN73 — Devil Square's stages and Play, asked while this PR was open.
  10. map lists name Devil Square's stages, which OpenMU sends — Devil Square 1–4 are stages of map 9 and 5–7 of map 32, so data could say "Devil Square 1–4" but not "Devil Square 2". OpenMU sends the extended client the map's discriminator (feat: send the map's discriminator (Devil Square stage) to the extended client OpenMU#7) at the end of two packets one byte longer than the originals, which other clients still get: MapChangedExtended (C3 1C 0F, 16 bytes) at 15 with a map change or teleport, and CharacterInformationExtended (C3 F3 03, 93 bytes) at 92 when the character enters the world, so a character which logs in again in Devil Square keeps its stage. The client keeps it next to the server map; a shorter packet and a revival set 0. (This commit read byte 10 of the original MapChanged; OpenMU#7's review moved the discriminator, and fix(maps): the stage comes where OpenMU sends it now, also when entering the world reads it there.) Every map list may name a stage, {"map": 9, "stage": 2}, next to plain numbers; a number names all its stages (Data::Maps::MapRef, read, written and matched in one place). The map picker shows Devil Square's seven stages; any can be picked, and a map with every stage picked is written as its number.
  11. fix(editor): the monster skill and player skill rows have ids of their own — with a row in both tables, the player skill row's Remove shared the id of the monster skill row and a click did nothing.
  12. Play in Monster Attacks — Play on each skill row plays its animation once in Monster Preview with the model's attack sound and the attacks' sound, then the model stands; Play next attack plays what the next other attack plays (the rotation in turn, the generic pattern and the draws as the game counts them) and says which; From the start starts the counts again. Skill effects do not play yet. The draw and the generic step are the game's own functions, made callable (code unchanged).
  13. docs(monsters): the answers to Q-MN74 and Q-MN75 — Monster Preview plays the sound events (Q-MN74); the sound slots become sound events in a PR of their own right after this one (MNS, Q-MN75), which the plan gets before 3a.
  14. Monster Preview plays the sound events — Play was silent for the 29 monsters whose attack sound is a sound event (Elbeland, Kanturu, Empire Guardian and others): the preview played only the sound slots. The sound events code gets PlayEvents, which the game's Play and the preview call (the game's draws, order and checks unchanged); the preview plays a model's events when an animation starts, at each loop of stop1 and stop2 and frame by frame in a walk, as PlayMonsterSound runs.

Comparison (commit 8)

A one-time recorder ran on the commit before the switch and on the switch: every monster with attacks on 28 server maps (where OpenMU's Season 6 places them, 32 included; each old handler's maps; maps without a handler), with the skills its attacks name and unnamed ones, two SwordCounts, two seeds, two frame rates and two attacks in a row, recording the animation, the skills after, SwordCount, the rotation count, the guards' AI, the height and the next rand() — 323,008 cases.

  • Every case on a map where the server places the monster, or where its old handler answered, is the same (Fire Golem and Dark Elf in Devil Square 5–7, Erkanne in Loren Market, Maya, Selupan, the Empire Guardian bosses' rage, the traps and Bali included).
  • 168,000 cases differ: a monster on a map where neither is true (1,940 pairs of 74 monsters: a Kanturu monster in Lorencia, an Empire Guardian monster on another weekday's map, a Battle Castle guard outside Battle Castle, where its creator gives it another model). They now play their attacks instead of the generic pattern.

Decided by me

  • Erkanne's "no animation" in Loren Market became a map variant, so its handler code could go.
  • The map picker also groups Doppelganger 1–4, Empire Guardian 1–4 and Karutan 1–2 (each one name in the game today); the data still names each map by its number.
  • No format version step for Models.json's renamed keys, nor for stage objects in its lists (the shipped file has none).
  • Monster Preview opened by Play goes beside Monster Attacks when both are tabs of one dock node (as in the first layout), the node split in half, so Play does not hide the window it was clicked in; in another node its tab comes to the front.
  • Monster Preview plays the sound events on any map and at any distance (the game: only on the model's maps and within 500 units of the hero), with the death effect counted as armed, so the Snowman's death sound is heard.
  • The stage comes from MapChangedExtended and CharacterInformationExtended only; a stage the picker does not know (hand-written data, e.g. {"map": 0, "stage": 3}) is named "Lorencia stage 3" and kept.

Testing

  • Debug editor build with all test targets; ctest -j 3 -E rml-theme: 1,767/1,767 pass on 2a2f5f9 (one GPU test skipped). The 24 RmlUi theme tests ran on commit 12: 20 pass, four stop on an RmlUi assert dialog (URL.cpp:20) in local Debug builds on this machine (also on main).
  • New tests: rotations in turn and per monster, generic equal to a monster without attacks at every count, reading/writing/errors of rotations and map variants, a variant on its maps (Devil Square 5–7 by server map 32), the shipped Fire Golem and Erkanne variants, the guards' attack state, the Monster Attacks choices and Map row, the map picker (rows, names, info, clicks), map names wherever the hero is, the server map and files folder, a sound event list naming 32. Stages: reading and writing {"map", "stage"} and its errors, a map and its stage in two variants, a variant of one stage playing only there, a sound event list with a stage, the stage from MapChangedExtended (at 15; the 15-byte MapChanged none, whatever its bytes 10 to 14) and from CharacterInformationExtended (at 92; a 92-byte packet none), the map manager's stage, the picker's stages (names, info, choosing one, a whole map giving way to its other stages, every stage becoming the map, clicks). Play: rotations, the generic pattern and draws as the game counts, Play opening the preview beside Monster Attacks in the first layout, Play next attack and From the start; the two skill tables' rows. Sound events: PlayEvents on a map the events do not name, frames and the death effect; Play in the preview with a model's events (attack, appear, the Snowman's death), none at a walk's start, and a slot sound as before. Each new test fails against a mutation of the code it covers (34 + 21 + 8 + 2 mutations).
  • clang-format 21.1.8 on the changed lines and cppcheck on the changed files: clean.
  • Not covered by a test of its own: ReceiveTeleport and ReceiveJoinMapServer setting the stage (they need a hero; the readers they call are tested), the map texture folders and map parts by stage (they call the same tested Names with the server stage), and the preview's walk sounds frame by frame (they need the preview drawn; the events of a frame are tested).
  • In game (owner, Release editor build of commit 12): the map picker's stages, Play and Play next attack work. No sound played; the test build's folder lacked the client's sound files, which every sound needs (not this PR). The sound events in Monster Preview (commit 14): not tried yet. Stages in game need a local OpenMU with feat: send the map's discriminator (Devil Square stage) to the extended client OpenMU#7.

The attacks PR (MN2b) lets the attack data decide on every map (Q-MN64):
of the 115 numbers with attacks, OpenMU places only Fire Golem 291 outside
its handler's map, as the boss wave of Devil Square 5, where it keeps the
generic pattern through a map variant (Q-MN65, D62). A variant's attacks
replace the entry's (Q-MN68). Data names maps one way, by the number the
server sends; the client keeps it, so Devil Square 5–7 (32) stays apart
from 1–4 (9) (Q-MN66, Q-MN67, D67). A rotation in `otherwise` plays in
turn with its own count; `generic` keeps today's pattern (Q-MN69).

The content roadmap's later row gets maps as data: names, groups, server
numbers, files folders and files shared between maps.
A monster's attacks can now play several animations in turn for any
other attack (monsters design, Q-MN69): "otherwise": ["attack1",
"attack3"] plays attack 1, attack 3, attack 1, ... with a count of each
monster's own (CHARACTER::AttackRotation, 0 when the monster is created),
which a skill entry that plays does not move on. "otherwise": "generic"
plays the generic pattern as a monster without attacks does; it is the
pattern's code moved into NextGenericAttack, which SetPlayerAttack's and
SetPlayerMagic's monster branches call as before. A rotation could not
count by SwordCount: SetPlayerAttack adds 1 to it on every attack and the
pattern 1 more, so other lists would play out of order.

Monster Attacks offers an animation, a rotation (with Remove and Add an
animation), the generic pattern or a draw; the checks look at each
animation of a rotation, and at attack 1 and 2 for the generic pattern.
The list writes a rotation on one line. Texts in English and German;
docs/monster-data.md describes the forms of otherwise.
GetMapName asked whether the hero is in the Balgass barracks, the Balgass
refuge or Illusion Temple instead of comparing the map it was given.
While the hero was in the barracks, every map that comes later in its
checks (Lorencia, Noria, the Swamp of Peace, ...) was named "Balgass'
Barrack": a party member's map in the party window and the portal and
revive maps of PortalMgr; and Illusion Temple was named only while the
hero was in it. The three checks compare the map now.

The map tools' map picker (monsters design, D67) names every map with it.
LoadWorld turns the server's map 32 (Devil Square 5-7) into world 9, so
that Devil Square's files load, and nothing remembered 32. SetServerMap
keeps the number the server sent next to WorldActive, and GetServerMap
returns it for the data that names maps by the server's numbers
(monsters design, D67); where WorldActive was set alone, as the tests and
the photo viewer do, it returns WorldActive.

GetFilesFolder says which Data/World<n> and Data/Object<n> folders a map
loads: one for all rounds of Blood Castle, Chaos Castle, Kalima, Illusion
Temple and Devil Square. LoadWorld's terrain files and Load's world
objects used two copies of that choice; both call it now, with the same
result for every map (behaviour-identical). The map picker of the monster
tools shows it.
Models.json names maps one way now, by the numbers the server sends
(monsters design, D67): worldTextureFolders, a part's worlds and
soundEventWorlds become mapTextureFolders, maps and soundEventMaps, and
the game compares them with the map manager's server map (GetServerMap) instead
of WorldActive. None of the lists names 9 or 32, the only numbers where
the two differ, so the game loads and plays the same on every map; the
renamed file reads and writes back unchanged. A list that names 32 now
holds in Devil Square 5-7 and not in 1-4 (test).

The file keeps format version 1: the renamed keys are new names in the
one copy that ships with the client.
The editor picks maps one way (monsters design, D67): a button that names
the chosen maps opens the list of the maps a server sends, each with its
server number and the world folder it loads (GetFilesFolder). The rounds
of an event are one row under the event's name: Devil Square 1-4 and
5-7, Blood Castle 1-8, Chaos Castle 1-7, Kalima 1-7, Illusion Temple 1-6,
Doppelganger 1-4, Empire Guardian 1-4 and Karutan 1-2; the row's box
picks all rounds, its arrow shows them. A list with all rounds of an
event names the event.

Monster Model's sound events pick their maps in it instead of typing
their numbers. Map variants of attacks use it next. docs/monster-data.md:
the map picker.
What a monster does differently on some maps is a map variant of its
entry (monsters design, D62, Q-MN65): "mapVariants": [{"maps": [32],
"attacks": {...}}]. On the variant's maps, by the server's numbers (D67),
its attacks replace the monster's as a whole (Q-MN68); the game asks
GetAttacksOnMap with the server map, so a variant for Devil Square 5-7
(32) does not play in 1-4 although both load as world 9. A map in two
variants of a monster is fatal; a variant without attacks changes nothing
(a warning). The setup fields join the variants in their PR.

Monster Attacks gets a Map row: All maps, each variant named by its maps,
and Add a map variant, which starts with the monster's attacks; Plays on
picks a variant's maps in the map picker, Remove the map variant removes
it, and the tables edit the chosen variant's attacks. The attack checks
look at each variant's attacks under its field, which opens Monster
Attacks. Texts in English and German; docs/monster-data.md: map variants.

No entry has a variant yet; the next commit gives the Fire Golem its
Devil Square one.
SetPlayerAttack's map handlers chose a monster's attack animation only for
the numbers they listed, each on its maps; any other number, and a listed
one on another map, played the generic pattern (monsters design, Q-MN62,
Q-MN64). Now a monster's attacks play on every map, and a map variant
says where they differ. The handlers that only played attacks go: Hellas,
the Hunting Ground, Aida, Crywolf and Devil Square, Kanturu 1st and 2nd,
the Balgass barracks, Illusion Temple, the Swamp of Quiet, Bali's branch,
the plain cases of Empire Guardian 1 to 3 and Raklion, and CheckMonsterSkill.
What stays is map code that is no choice of animation: the Battle Castle
guards' attack state (SetGuardAttackState), Maya's scene, Selupan's
height, sounds and effects, the Empire Guardian bosses' rage, and the
traps' effects.

Two numbers attacked differently by map where the server places them, and
keep that in their data:

- Fire Golem 291, Devil Square 5's boss, played the generic pattern there
  (its handler checked the Hunting Ground only): a map variant for map 32
  plays "generic". The owner takes the pattern as intended there.
- Erkanne 507 played no animation in Loren Market (a handler answered
  with nothing): a map variant for map 79 plays "none" and clears no
  skill.

Empire Guardian 2's case for the Defender (played nothing, but Empire
Guardian 1 always answered first) goes with them.

Monster Attacks shows the map code that runs with a monster's attacks
instead of the handlers that read them; the check for attacks that no
handler reads goes, since none is left unread.

The comparison (one-time, a recorder run on the commit before and on this
one): every monster with attacks on 28 server maps (the maps OpenMU's
Season 6 places them on, 32 for Devil Square 5-7 included; each handler's
maps; maps without a handler), with the skills its attacks name and
unnamed ones, two SwordCounts, two seeds, two frame rates and two attacks
in a row, recording the animation, the skills after, SwordCount, the
rotation count, the guards' AI, the height and the next rand(): 323,008
cases. Every case on a map where the server places the monster or its
handler answered is the same. 168,000 cases differ, all a monster on a map
where neither is true (1,940 pairs of 74 monsters: a Kanturu monster in
Lorencia, an Empire Guardian monster on another weekday's map, a Battle
Castle guard outside Battle Castle, where the creator gives it another
model): they now play their attacks instead of the generic pattern.
Devil Square's stages and Play in Monster Attacks, asked while the attacks
PR was open:

- Q-MN70: OpenMU sends the extended client the discriminator of its map in
  MapChanged byte 10 (Mosch0512/OpenMU#7), the stage of Devil Square; other
  clients get 0 there as before. Q-MN66's "not needed" changes.
- Q-MN71: map lists name a stage as {"map": 9, "stage": 2}; a number names
  all its stages; the picker shows the seven stages one by one.
- Q-MN72: a group's levels are maps of their own or stages of one map.
- Q-MN73: Play on each skill row and Play next attack, in Monster Preview
  with the attack sounds; skill effects come with the skill tools.
Devil Square 1-4 are stages of map 9 and 5-7 of map 32, so data could pick
"Devil Square 1-4" but not "Devil Square 2" (Q-MN70, Q-MN71).

- MapChanged (C3 1C 0F) carries the stage at byte 10 from OpenMU to the
  extended client (Mosch0512/OpenMU#7); GetTeleportStage reads it when the
  packet is long enough. The map manager keeps it next to the server map
  (GetServerStage, 0 where WorldActive was set alone); entering the world
  and a revival set 0.
- Every map list in data (map variants, mapTextureFolders, a part's maps,
  soundEventMaps) may name a stage, {"map": 9, "stage": 2}, next to plain
  numbers; a number names all its stages. Data::Maps::MapRef reads, writes
  and matches them in one place. A map and its stage in two variants of a
  monster is fatal like a map twice.
- The map picker lists Devil Square's seven stages in its row; any of them
  can be picked, a map whose every stage is picked is written as its
  number, and the row's info names the stages.
…r own

Monster Attacks drew both tables' rows under the same ImGui ids: with a row
in each table, the player skill row's Remove (and its animation combo and
Play) shared the id of the monster skill row above it, and a click on it did
nothing. Each table's rows now sit under an id of their own.
The owner asked to see what the attacks play (Q-MN73):

- Play on each skill row plays its animation once in Monster Preview (and
  opens it), with the model's attack sound and the attacks' own sound; then
  the model stands, as after an attack in the game. Skill effects do not
  play yet. Where Monster Preview is a tab of the same dock node as
  Monster Attacks (as in the first layout), one would hide the other: the
  node splits once and the preview takes its right half (Layout::ShowBeside,
  at the next dock space); in another node its tab comes to the front.
- Play next attack plays what the monster's next other attack plays and says
  which: the rotation in turn, the generic pattern and the draws as the game
  counts them for one monster (SetPlayerAttack adds 1 to SwordCount for each
  attack, the pattern 1 more); From the start begins the counts again.
- The draw and the generic pattern's step are the game's own functions
  (DrawAttack, NextGenericAttack on a count), moved out of the anonymous
  namespace and the CHARACTER version; their code is unchanged.
Monster Preview plays the sound events too, in this PR (Q-MN74); the
sound slots become sound events in a PR of their own right after the
attacks PR, MNS (Q-MN75). The plan gets the Sounds PR before 3a.
Play in Monster Attacks was silent for the 29 monsters whose attack sound
is a sound event (Elbeland, Kanturu, Empire Guardian and others): the
preview played only the sound slots (Q-MN74).

The sound events code gets PlayEvents, which the game's Play and the
preview call: the events of an animation at a frame, their chances drawn
and picks picked, in order. The game adds the hero's distance and the
model's maps as before; the preview plays them on any map and at any
distance, with the death effect counted as armed (the Snowman's death
sound), when an animation starts, at each loop of stop1 and stop2 and
frame by frame in a walk, as PlayMonsterSound runs.
# Conflicts:
#	src/source/World/MapInfra/MapManager.cpp
ReceiveTeleport and ReceiveRevival loaded the world when WorldActive
differed from the map in the packet. WorldActive is the loaded world, so in
Devil Square 5-7 (server map 32, world 9) a move to map 9 counted as the same
map: the world did not load and GetServerMap() stayed 32, so the map variants,
sound events and texture folders of 32 applied in Devil Square 1-4. The other
way round, every MapChanged inside Devil Square 5-7 loaded the world again
(9 against 32).

Both now ask the map manager whether the server map is loaded
(IsServerMapLoaded, GetServerMap() == the packet's map).
…new names

worldTextureFolders, a part's worlds and soundEventWorlds became
mapTextureFolders, maps and soundEventMaps without a format version step.
In a file that still had the old names they were unknown keys, a warning
only, and their maps were lost: a part without maps opens with its model on
every map (the Kundun pieces, the Totem Golem's), and the texture folders
and the sound events' map list were dropped.

Each old name is now fatal and says its new name; it is no unknown key as
well.
… handler

GMNewTown::SetCurrentActionMonster returns false on every map, so its call
in SetPlayerAttack chose nothing; the map code left there is the guards'
state, Maya's scene, Selupan and the Empire Guardian bosses' rage. The call
and the empty handler go.
The Monsters.json reader had its own rule for two map list entries that
name the same map or stage (a map in two map variants). It moves next to
Names as Data::Maps::Overlaps, so what an entry with or without a stage names
is said in one file.
…th the model standing

Monster Preview's Advance returned at a held animation's last frame before
it looked whether Play had started the attack, so an attack (or appear)
marked holdLastFrame stayed on its last frame and the preview never stood
the model. BMD::PlayAnimation ends a held animation when it reaches its last
frame, and SetPlayerStop follows; the preview now stands the model there too.

Advance is public, for a test that plays a held and an unheld attack frame
by frame.
The generic pattern and a draw keep the rotation in otherwise (it is not
written while they are chosen). Choosing A rotation again resized the list
to two, so a rotation of three or more lost its later turns. Only one
animation is made two now.
… name

A map or stage in two variants of a monster is fatal when the monsters are
read, so Save refuses them, and until then the game plays the first variant
there. Monster Attacks warned only about a variant without maps. It now also
names the maps of the shown variant that another variant names too
(Data::Monsters::FindMapsOfOtherVariants, stages by Data::Maps::Overlaps).
…acks on that variant

A problem of "monster 291 mapVariants[0].attacks" opened Monster Attacks,
but selecting the monster showed All maps, the attacks the problem is not
about. Data Checks now tells Monster Attacks which attacks to show
(ShowMapVariant): the variant the field names (GetMapVariantOfField), or all
maps for the monster's own attacks.
Monster Attacks' Play next attack repeated Play's steps after the choice:
the draw's pick, the generic pattern's next animation and the rotation's
next turn. They are one function now, ResolveAttackAnimation, on the
character's counts in the game and on the tool's counts in the editor, so
the preview cannot drift from the game. The game plays the same.
PlacedDockId and ApplyShowBeside were added between BesideBrowser and its
comment, which then stood above PlacedDockId's own.
…dDockId

ShowBeside's PlacedDockId repeated FindDockNode's lookup: the window's dock
node, else its dock id, else the one imgui.ini keeps. FindDockNode now gets
the node of PlacedDockId's id, so the place of a window is looked up once.
GetLoadedWorld compared with a bare 32, the map names had their own
SecondDevilSquareMapId and the map picker its DevilSquare5To7. The constant
moves to MapManager.h, next to the worlds, and all three use it (coding rule
3, no hard-coded values).
…ellas

The Illusion Temple range was written out in IsCursedTemple, in
GetFilesFolder and in the map names' EventMapName, because IsCursedTemple
asked only about the hero's world. It takes a map now (-1 for the hero's),
as InBloodCastle, InChaosCastle and InHellas do, and the other two use it.
HeroMapScope put back only WorldActive. The server map tests end on
SetServerMap(32), which left server map 32 for world 9: a later test in the
binary that set WorldActive to 9 alone got GetServerMap() 32 and the stage
it left. The scope now puts the server map and stage back too.
…ing the world

Mosch0512/OpenMU#7 no longer writes the discriminator into byte 10 of the
original MapChanged, which stays as it was (OpenMU's coding rule 2). The
extended client gets it at the end of two packets that are one byte longer
than the originals:

- MapChangedExtended (C3 1C 0F, 16 bytes) at 15, with a map change or a
  teleport. GetTeleportStage reads it there; the 15-byte MapChanged has
  none, and its bytes 10 to 14 aren't initialized.
- CharacterInformationExtended (C3 F3 03, 93 bytes) at 92, when the
  character enters the world. A character which lost its connection in
  Devil Square logs in again on its stage's map without a map change, so
  entering the world sets the stage from the packet (GetJoinMapServerStage)
  instead of 0, before LoadWorld loads the stage's map parts. The struct
  stays 92 bytes, so safe_cast still takes the packet of a server which
  doesn't send the stage.

Q-MN70 in the design and docs/monster-data.md name the two packets.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant