Repository navigation
Attacks: the attack data decides on every map, rotations, map variants, one way to name maps - #135
Merged
Merged
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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,
otherwisecan 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
"otherwise": ["attack1", "attack3"]plays in turn, counted per monster from its creation (CHARACTER::AttackRotation);"otherwise": "generic"plays today's pattern exactly (its code moved intoNextGenericAttack, whichSetPlayerAttackandSetPlayerMagiccall as before). A rotation cannot count bySwordCount:SetPlayerAttackadds 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.LoadWorldturns the server's map 32 (Devil Square 5–7) into world 9 and forgot 32;GetServerMapkeeps it.GetFilesFolderis the one place that says whichData/World<n>folder a map loads (two copies before; same result for every map).Models.json'sworldTextureFolders, parts'worldsandsoundEventWorldsbecomemapTextureFolders,mapsandsoundEventMaps, 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)."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).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.MapChangedExtended(C3 1C 0F, 16 bytes) at 15 with a map change or teleport, andCharacterInformationExtended(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 originalMapChanged; 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.PlayEvents, which the game'sPlayand 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, asPlayMonsterSoundruns.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 nextrand()— 323,008 cases.Decided by me
Models.json's renamed keys, nor for stage objects in its lists (the shipped file has none).MapChangedExtendedandCharacterInformationExtendedonly; a stage the picker does not know (hand-written data, e.g.{"map": 0, "stage": 3}) is named "Lorencia stage 3" and kept.Testing
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).genericequal 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 fromMapChangedExtended(at 15; the 15-byteMapChangednone, whatever its bytes 10 to 14) and fromCharacterInformationExtended(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:PlayEventson 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).ReceiveTeleportandReceiveJoinMapServersetting 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 testedNameswith the server stage), and the preview's walk sounds frame by frame (they need the preview drawn; the events of a frame are tested).