Repository navigation
Conversation
The sound slots play at moments of the game, not with animations: when an attack starts, the monster is hit, it dies, it is set to stand and at each walk step. Q-MN76: the converted sound events name these moments (`on`) and play where the slots play today, whatever the animation; any event may use them. Q-MN77: the death moment plays in Chaos Castle too, next to the explosion. The MNS phase and its details say how; the chain is six PRs since the sounds PR joined it.
…nywhere and at the monster What the sound slots do and the sound events could not (Q-MN76), so the slots can become events: - `on`: the moments attack, hit, death, stand and walk, where the slots play (SetPlayerAttack, SetPlayerShock, SetPlayerDie, SetPlayerStop, SetPlayerWalk), whatever the animation. An event names animations or moments. - `subType` and `notSubType`: the second set of SubType 9. - `heardAnywhere`: no 500-unit cut-off and no map list. - `atMonster`: the character as PlayBuffer's object, which does not start the sound again while it plays. - `pick` with one sound: the sound in one draw of two, else none (a slot pair whose second slot is empty). SoundEvents::PlayMoment plays a character's events at a moment; Play and the preview's PlayEvents take the situation (animation, frame, moment, death effect, SubType, heard). The game plays nothing new yet: no data names a moment.
…etons play none The Skeleton monsters are the player model with a skeleton SubType, and SetPlayerStop, SetPlayerWalk, SetPlayerAttack and SetPlayerDie played the sound slots of their model as for a monster. Nothing sets the player model's slots: BMD left them as the memory was, so a skeleton played a sound by that value (in a Debug build sound 210 when set to stand and when walking, next to its bone sound). A BMD now starts with no sound in any slot, as the model loader sets them for a model without slots (P9).
The 74 models with sound slots get sound events instead (monsters design, MNS, Q-MN75 to Q-MN77), 209 in all, in the order the slots played: - idle on stand and walk, one time in 16 by rand_fps_check, then a pick (the Balrog only on stand: its bone sound comes first while it walks); - attack on attack and hit (the Assassin's only on attack, as its slot played no hit sound); - die on death; - the second set of the Death Centurion and Shriker models with subType 9, the first with notSubType 9. All are heard anywhere and played at the monster, as the slots were. A pair whose second slot was empty is a pick with one sound. The five places that played the slots play the events of their moment: SetPlayerStop and SetPlayerWalk (a player still draws for its Fenrir and a skeleton's bone sound), SetPlayerAttack, SetPlayerShock and SetPlayerDie, whose death events play in Chaos Castle too, next to the explosion (Q-MN77). Models.json is format 2 and refuses soundSlots; PlaySlotSound, HasSlotSound, MonsterSlotSound, BMD::Sounds, the slot reader, writer and checks, and Monster Model's slot rows go. Monster Preview plays the events of the moment where it played a slot. Comparison: a one-time recorder ran every monster on 22 maps (those the sound events name, Lorencia, Devil Square 1-4 and 5-7, Chaos Castle 1 and 7), with its SubType and SubType 9 (or 0), near and far from the hero, two seeds and two frame rates, through SetPlayerStop and SetPlayerWalk (24 calls each), SetPlayerAttack, SetPlayerShock, SetPlayerDie (death effect armed and not) and the events of every animation at three frames, recording each sound, whether the monster was its object, and the next rand() and engine draw. On the commit before and on this one, 191,840 cases: the same sounds in the same order with the same rand(), except - the death in Chaos Castle, which plays the death sound too (Q-MN77); - SubType 9 on a model without a second set, which plays its sounds now (only the Death Centurion and Illusion of Kundun have SubType 9); - the stray slot sound of the models no entry opens (the skeletons and traps), which the commit before removed; - fewer rand_fps_check draws for a monster without idle sounds (its events draw, the code no longer does), with the same sounds. The Molt (a model without a body, whose sounds are not loaded) was left out of the second run: numbering its sound files shifts the numbers of later ones.
… and death play their moments The Bull Fighter's walk plays its idle events (in a safe zone, where a walk does not read the hero's equipment); its death in Chaos Castle plays its death sound, then the explosion (Q-MN77); Monster Preview's shock plays the hit moment's events and its death the death moment's.
…ations, by SubType, anywhere and at the monster The sound events table gets what the events got (Q-MN76): - When: a combo of the moments (attack, hit, death, stand, walk) and the animations; picking one of the other kind makes the event one of it, and the last one stays. It shows "attack1, attack2" or "on attack, hit". - SubType: any, only n or not n (a new one names 9, the second set of the Death Centurion and Shriker models). - Anywhere (heard at any distance and on every map) and At monster (the sound is not started again while it plays). - Pick with one sound: the sound or none. Texts in English and German.
monster-data.md: the model example and the field list without sound slots; the sound events name animations or moments (a table of where the game plays each), with subType and notSubType, heardAnywhere and atMonster and a pick with one sound; format 2 refuses soundSlots; Monster Model's When, SubType, Anywhere and At monster; Monster Preview plays the events of the moment of each animation.
With "One of two" set, Play on a sound event always played the first sound, so a pick of DSIDLE1 and DSIDLE2 never let the second be heard. Play now draws which one, like the game does (one sound: that one each time); without a pick it plays all of them together, as before. The event's chance is still not drawn, so Play always makes a sound.
…ters name Sound data moves out of the models into sound sets (Sounds.json) that every monster names; frames become cues on the models, shown and edited from Monster Preview and Monster Sounds; the Chaos Castle wizard look is a random variant with its own set.
The monsters design's answers Q-MN78 to Q-MN83:
- Sounds.json holds the sound sets: their sound files, sound events and the
maps they play on. Every monster names its set (soundSet); a model holds
no sounds. The game plays the set of the character's monster
(CHARACTER::MonsterIndex) for the model it appears with, so the Death
Centurion and the Illusion of Kundun play their own sets and no event needs
SubType. A model opens with the sounds of the sets its monsters use with
it, which loads a sound where it loaded before.
- Frames become cues of the models ("step 1" = walk frames 1 to 2); an event
plays on cues, so a set fits any model with its cues.
- The ranged Chaos Castle soldiers' wizard look is a random variant with its
own set: the code still draws the look, the variant of the drawn model
applies.
- One conversion: 139 sets from the 146 models' sounds (fully alike lists
share one), 312 monsters name one, 12 models get their two step cues;
Models.json format 2 refuses sounds, soundEvents and soundEventMaps, the
sets' reader subType, notSubType and frames.
- Editor: Monster Sounds edits the sets, the monster's and its variants'
sets, and on a cue's event the cue's frames (Use the preview's frame, a
new cue at the preview's frame, removing a cue's last event asks about the
cue); Monster Preview shows the cues as tags (hover: frames and sound;
click: Monster Sounds at the event), Add a sound at this frame and a
Variant switch; Monster Model shows the cues and the monster's set; Data
Checks has the sound sets and what the files name of each other. Texts in
English and German.
Sounds.json read and written back, the writer's layout, every wrong value with its set and field, the old event fields refused (Q-MN78, Q-MN79); a monster's set and its random variants' (Q-MN83); the checks between the monster list, the model list and the sets; and the shipped sets: they load clean, are written as the writer writes them, the four SubType sets have their own files, the ranged Chaos Castle soldiers have the wizard variant, twelve models have their step cues, and sets that share a sound id load it alike.
monster-data.md: Sounds.json and its sound events (animations, cues or moments), the monsters' soundSet and randomVariants, the models' cues, the checks between the files, Monster Sounds, Monster Preview's cue tags, Add a sound at this frame and Variant, and Save and Revert with three files. The editor README lists MuMonsterSoundsUI.
Main and this branch both added editor texts at the end of Editor.en.resx and Editor.de.resx; both sides' texts are kept.
…s while they are typed Monster Preview draws before Monster Sounds in a frame, so the draft that Monster Sounds gave only in the frame it drew never reached the preview, and Monster Model's draft came first for the cues too. The preview now takes Monster Sounds' draft of this frame or the one before, and its cues before Monster Model's (Q-MN81).
…that plays the shown set The cue rows changed the cues of the selected monster's shown look also while Monster Sounds showed another set: one picked in the list, a random variant's set opened while the entry's look was shown, or the set of the monster selected before, which stays shown when the new one names none. A cue's frames then changed on a model the set's monsters do not have, and "New cue at the preview's frame" moved the set's event onto a cue they lack. The cue rows now take the look's model only while it plays the set shown; otherwise they say to select a monster of the set.
…t a store freed A sound event row kept its event, and a cue row its cue, while it stored a change, and the store took the draft back from the data at once: the new set replaced the draft's lists, the old event and cue were freed, and the rest of the row read them and wrote the chance's clamp into freed memory. The editor's drafts can now take the data back at the next frame (ReloadAfterStore::NextFrame); Monster Sounds' set and model drafts do, the other tools keep taking it back at once.
… the fields when nothing is stored Add a file checked the file only. A sound with an id that is not a SOUND_ id was refused by the set's save without a word, and the file and id fields were cleared anyway. The checks are one function now (FindNewSoundProblem) that also checks the id; the button stays off with the reason as its tooltip, and the fields are cleared only when the set has the file.
…t sets load from different files an error The sound set checks let a set have two sounds with one name (the same id, or the same file without one), of which an event always played the first, and let two sets load one SOUND_ id from different files, so that the id played the file of whichever model opened last. The first is fatal now, the second an error that names the set and file that loaded the id first; Add a file refuses an id another sound of the set has.
…look lacks when it plays the entry's set A random variant without a set of its own plays the entry's set on its own model, but the check of the cues looked only at the entry's model: an event on a cue the variant's model lacks never played for that look, without a warning. The variant's model is checked with the entry's set now.
… any more An event moved from a cue to a moment or another cue left the cue on the model, and no tool removed a cue: each "New cue at the preview's frame" that was tried and left stayed in Models.json. Monster Model's Cues list has Remove for a cue that no event of a set its monsters play names; a cue in use says so in its tooltip.
…nge of the lists, not at each sound Each sound of a monster (a walk step played two lookups) found the set by turning the model names of the monster and its random variants into slots, a scan of every model name each, and each model that opened did that for every monster number. SoundSetLinks keeps the set of each look of each monster and the monsters of each model, built again when the monster list or the sound sets change; FindSoundSet and ModelLoader::FindSoundSetsOfSlot use it.
…inks, not with a scan each frame The cue rows' "a cue of the model, for N monsters" scanned every monster number and turned each model name into a slot on every frame the window drew. SoundSetLinks::CountMonstersWithModel gives the count from the links, and it now also counts the monsters that appear with the model as a random variant, which a change of its cues reaches too.
…ined once The channels of a sound, a sound event's chance and the sounds of a pick had their limits in the reader and again in Monster Sounds and the sound event rows, and Monster Preview had a copy of the rows' frame text. The limits are in MonsterSoundSet.h now (MaxSoundChannels, MaxSoundChanceOneIn, PickSoundCount) and the frame text is SoundEventsEditor::FrameText, so the editor cannot let through a value the save refuses.
…Preview keep the cue alike Add a sound at this frame kept its new cue 0.1 frames long with a bare 0.1f, while the cue rows of Monster Sounds named it MinCueFrames, so the two could drift apart (CODING_RULES.md, 3). Both call SoundEventsEditor::KeepCueFrames now.
The reader checked that a cue's first frame is below its second on the file's numbers and then kept them as floats: two close numbers could be one float, a cue that never plays, and a frame past the floats' range an infinite one, without a problem. The frames are compared and checked as floats now.
Main and this branch both added editor texts at the end of Editor.en.resx and Editor.de.resx again; both sides' texts are kept.
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 third of the six PRs that finish the data-driven monsters work (design, "Pull requests and phases", MNS): the sound slots of 74 models become sound events that play at moments, and then all monster sounds move out of the models into sound sets (
Data/Monsters/Sounds.json) that every monster names, with cues on the models for sounds at frames and a random variant for the Chaos Castle wizard look. The game sounds as before.The Attacks PR (sven-n#886) is merged, so this PR now shows only its own commits.
Commits (the sound slots)
on: attack, hit, death, stand, walk) and play where the slots played, whatever the animation (Q-MN76); the death moment plays in Chaos Castle too, next to its explosion (Q-MN77). The chain is six PRs since the sounds PR joined it.onmoments (an event names animations or moments),subType/notSubType(the second set of SubType 9),heardAnywhere(no 500-unit cut-off, no map list),atMonster(the character asPlayBuffer's object, which does not start the sound again while it plays), and apickwith one sound (the sound one time in two, else none: a slot pair whose second slot was empty).SoundEvents::PlayMomentplays a character's events at a moment. No data used them yet.BMDstarted with no sound in any slot.standandwalk(one in 16 byrand_fps_check, then a pick; the Balrog's only onstand, its bone sound comes first while it walks), attack onattackandhit(the Assassin's only onattack), die ondeath, the Death Centurion and Shriker models' second set withsubType9 and the first withnotSubType9; all heard anywhere and at the monster. The five places that played the slots play the events of their moment (SetPlayerStop,SetPlayerWalk,SetPlayerAttack,SetPlayerShock,SetPlayerDie).Models.jsonis format 2 and refusessoundSlots;PlaySlotSound,HasSlotSound,MonsterSlotSound,BMD::Sounds, the slot reader, writer and checks and Monster Model's slot rows go. Monster Preview plays the events of an animation's moment where it played a slot.Comparison (commit 4)
A one-time recorder ran every monster on 22 maps (those the sound events name, Lorencia, Devil Square 1–4 and 5–7, Chaos Castle 1 and 7), with its SubType and with SubType 9 (or 0), near and far from the hero, two seeds and two frame rates, through
SetPlayerStopandSetPlayerWalk(24 calls each),SetPlayerAttack,SetPlayerShock,SetPlayerDie(death effect armed and not) and the events of every animation at three frames, recording each sound, whether the monster was its object, and the nextrand()and engine draw. Before the change (on the Attacks head) and after it, 191,840 cases: the same sounds in the same order with the samerand(), exceptrand_fps_checkdraws for a monster without idle sounds (89,040 stand and 89,040 walk steps): its events draw, the code no longer draws for it; the same sounds and the samerand().The Molt (a model without a body, whose sounds are not loaded) was left out of the second run: numbering its sound files there shifts the numbers of later files; its events play its own unloaded sounds, so it is silent either way.
Decided by me (commits 2–8; the sound sets replace the SubType conditions, see below)
on,subType/notSubType,heardAnywhereandatMonster; heard anywhere and at the monster are two fields, both set for the converted events.soundSlotsstill reads; one with them is refused, with the new form in the message.Sound sets (commits 9–12)
After the owner tried the editor, the sound data moved out of the models (design Q-MN78 to Q-MN83, commit 9):
Data/Monsters/Sounds.json): a set holds sound files, sound events and the maps they play on, and every monster names its set (soundSet). A model holds no sounds. The Rogue and the Death Centurion share a model and now simply name different sets, so no event needsSubTypeany more; monsters of different models can share a set.step 1,step 2), and their events play"cues": ["step 1"]. A set then fits any model that has its cues.rand() % 2; OpenMU sends only the number of one Energy Ball monster), and the two looks played different attack sounds."randomVariants": [{"model": "MONSTER_MODEL_CHAOSCASTLE_WIZARD", "soundSet": "Chaos Castle Wizard"}]keeps the wizard's sound; the code still draws the look until MN4.Commits
soundSet,randomVariants, cues; the game plays the set of the character's monster (CHARACTER::MonsterIndex) for the model it appears with; a model opens with the sounds of its monsters' sets; the one conversion (139 sets, 312 monsters name one, 12 models get cues); the editor and Data Checks; texts in English and German.Then main is merged in (only the two editor text files conflicted, both sides kept).
Comparison (commit 10)
A second one-time recorder ran every monster on 22 maps (those the sound sets name, Lorencia, Devil Square 1–4 and 5–7, Chaos Castle 1 and 7), with the SubType its creator gives it, the ranged Chaos Castle soldiers in both looks, near and far from the hero, two seeds and two frame rates, through
SetPlayerStop,SetPlayerWalk,SetPlayerAttack,SetPlayerShock,SetPlayerDie(death effect armed and not) and the events of every animation at four frames (with the steps' 1.5 and 7.5). It wrote each sound by its file (orSOUND_*number), whether the monster was its object, and the nextrand()and engine draw. Before the sound sets (on commit 8) and after them, 97,196 cases:Decided by me (sound sets)
animations,onmoments orcues, one of the three.frames,subTypeandnotSubTypeare fatal and name what replaced them.Models.jsonstays format 2 (not released yet) and refuses its old sound fields.CHARACTER()starts as number 0) plays none; a monster that a map creator shows as a Bull Fighter on a map the server never sends it to no longer plays the Bull Fighter's sounds.Review fixes (commits 14–25)
An xhigh review of this PR found 12 problems, all in the editor and the data checks (the game's sounds stay as compared). One commit each, each with a test that a mutation of the fix fails:
ReloadAfterStore::NextFrame); Monster Sounds' two drafts do.SoundSetLinks), not with a scan of every model name at each sound and for every monster at each model open.MaxSoundChannels,MaxSoundChanceOneIn,PickSoundCountinMonsterSoundSet.h,SoundEventsEditor::FrameText).KeepCueFrames, no bare0.1f).Then main is merged in again (only the two editor text files conflicted, both sides kept).
Testing
ctest -j 3 -E rml-theme: 1,798/1,798 pass with the sound sets (one GPU test skipped), 1,813/1,813 after merging main in (bundled_font_assetsonce hit a log file another test was writing and passed on its own), 1,825/1,825 with the review fixes, and 1,853/1,853 with main merged in again (bundled_font_assetsagain hit the editor log and passed on its own). The effect types recorder ran again on its own and passed (it took 94 s of its 120 s; with three tests at once it ran out). The RmlUi theme tests were left out: they stop on an RmlUi assert dialog in local Debug builds on this machine.on,heardAnywhere,atMonsterand a pick with one sound, and their errors; moment events play only at their moments and animation events only in animations; heard anywhere far and on another map, at the monster; a pick with one sound in one draw of two;PlayMomenton a character; the shipped data (the Bull Fighter's moments, the Assassin's hit, the Balrog's walk, Queen Rainer's one-sound pick, the Dragon's loaded sounds); the game's stand, walk, attack, hit and death (and in Chaos Castle) on the Bull Fighter; Monster Preview's attack, hit and death; a skeleton's moments; a newBMDwithout slot sounds; format 2 refusingsoundSlots; Play's pick.soundSetandrandomVariantsand their errors; Models.json's cues and the old sound fields refused; the checks between the files (a missing set, a variant look the code does not draw, a cue the model lacks, a set no monster plays); the shipped sets (load clean, written as the writer writes, the four SubType sets with their own files, the Chaos Castle variants, the twelve models' step cues, loaded alike); a character plays its monster's set for its own looks only (not a player, not another model), the wizard look its variant's; one set on the cues of two models; a model loads its monsters' sets (the Death Centurion's ten files, the wizard's variant set); undo, redo, rename and remove of sets, refused sets, an undo refused after a change past the history, Save writing Sounds.json; Data Checks sending set problems to Monster Sounds; the editor's cue toggles and new cue names, the shown look of a variant, Monster Sounds' model draft in its frame and the next, and the three windows drawing without ImGui errors. Each new test fails against a mutation of the code it covers (35 mutations before the sound sets, 23 for them).