| Mar 4, 2026, 12:57 PM | |
|
Custom objects in MLLE, how to design
This is an idea Faw and I were chatting about some years back, and I never got around to implementing it in MLLE. Before I do any coding, though, it'd be good to make sure this is a workable design, so please sing out if you see any potential problems.
Currently MLLE has a "Configure Weapons" window hidden under the "JJ2+ Properties > Weapons" dropdown menu. If you change any weapons in the level (e.g. to one of these), MLLE takes the following steps (also described here) to make that happen:
Code:
Name = Duo Bouncers ImageFilename = duo bouncers.gif LibraryFilename = DuoBouncers.asc Initialization = DuoBouncers::Weapon() Options = Reverse behaviors:bool | Bounce through walls:bool:true The weapon's constructor passes a function (well, a delegate) DetermineReversedness to WeaponInterface::WeaponInterface's apply argument, which looks like this, where parameter corresponds to those two bytes in Data5: Code:
bool DetermineReversedness(uint, se::WeaponHook@, jjSTREAM@ parameter) {
if (parameter !is null && parameter.getSize() >= 2) {
parameter.pop(ReverseBehaviors);
parameter.pop(BounceThroughWalls);
}
return true;
}
For custom objects, instead of weapons, I think a similar system could work, but with a much simpler coding interface, because a) objects are far more variable than weapons and b) objects tend to only need a single jjObjectPresets entry, whereas a weapon needs to configure the bullet, the powered-up bullet, the pickup, the powerup monitor, and the +15 crate. For an interface, I think this should suffice: Code:
shared interface MLLEObject { bool Apply(uint8 eventID, jjSTREAM@ arguments = null); }
The library code would look something like this: Code:
namespace SlowFeet {
array
Code:
Name = Slow Feet LibraryFilename = SlowFeet.asc Initialization = SlowFeet::Pickup() Options = Ticks:uint:70 Hooks = onPlayer:SlowFeet::onPlayer Event = Slow Feet|+|Goodies|Slow|Feet Code:
#include "MLLE-Include-1.9o.asc" #include "SlowFeet.asc" const bool MLLESetupSuccessful = MLLE::Setup(array On the MLLE side of things, there'd be some window for assigning custom objects to event IDs, which would have room for defining object parameters, here the "Ticks" option. Then the "Event" line in the .ini would be read by MLLE and used in place of that event ID's normal event definition, so for example if you wanted to use event 100 for Slow Feet pickups, MLLE would use 100=Slow Feet|+|Goodies|Slow|Feet instead of 100=Tuf Turtle|-|Enemy|Tuf|Turt like normal. Should that window have limitations? Should events 1-32 not be allowed, or just show a warning if you try? What about when the script (or an included library) already overwrites the ini event for a given event ID? Like ///@Event 164=Beams|-|Trigger|Beams? Should you be allowed to try to overwrite the same event ID in both ways? I can think of objects that are more complicated... for example, the poison/antidote system from CloneV would need two jjObjectPresets entries, not just one. But that could be accomplished using the jjSTREAM argument to pass a second uint8. Other times you might want to have multiple instances of the same class, for different event IDs, and then they might have to rely more on delegates than the above example code. But that's all stuff that the library writer would need to handle. Another design decision is how to handle multiple objects that rely on the same standard hook function. Remember that if multiple weapons need onPlayer, you still only see MLLE::WeaponHook.processPlayer(play);, and that one method handles all the different weapons. But under the above model, for multiple objects, you'd see something like: Code:
void onPlayer(jjPLAYER@ play) {
SlowFeet::onPlayer(play);
Poison::sometimesInjurePlayer(play);
RecolorableSprings::checkYSpeed(play);
MLLE::WeaponHook.processPlayer(play);
}
Code:
interface MLLEObject { bool Apply(uint8, jjSTREAM@); }
interface MLLEObject_onPlayer { void onPlayer(jjPLAYER@) }
interface MLLEObject_onMain { void onMain() }
Then MLLE-Include-1.9o.asc would do something like this in the Setup function: Code:
uint8 eventID; jjSTREAM arguments; data5.pop(eventID); data5.pop(arguments); MLLEObject@ instance = initializerArray[0]; instance.Apply(eventID, arguments); MLLEObject_onPlayer@ instanceOnPlayer = cast<MLLEObject_onPlayer@>(instance); if (instanceOnPlayer !is null) someArrayOfOnPlayerFunctions.insertLast(jjVOIDFUNCPLAYER(instanceOnPlayer.onPlayer)); Code:
void ProcessPlayer(jjPLAYER@ player) {
for (uint i = 0; i < SomeArrayOfOnPlayerFunctions.length; ++i)
SomeArrayOfOnPlayerFunctions[i](player);
}
Code:
void onPlayer(jjPLAYER@ play) {
MLLE::ProcessPlayer(play);
}
Code:
namespace SlowFeet {
array
On a related note, one idea Faw suggested was not using .asc files for custom objects at all, but embedding all their code in the j2as, so the scriptwriter could easily make any level-specific changes they wanted. But again, that introduces a lot of room for the scriptwriter to make mistakes... (I know I could use the issues tracker, but the JCF should get more eyeballs.) Last edited by Violet CLM; Mar 4, 2026 at 01:18 PM. |
| Mar 19, 2026, 11:57 AM | |
|
Hey! It's been a couple weeks, still looking for opinions on these questions
|
| Mar 21, 2026, 03:11 AM | |||||
|
I don't feel 100% competent in answering this, but here's some opinions:
Quote:
Quote:
Quote:
Quote:
__________________
Mystic Legends http://www.mysticlegends.org/ The Price of Admission - Hoarfrost Hollow - Sacrosanct - other - stuff |
|||||
| Mar 21, 2026, 05:13 AM | |
|
One thing I'd like to see - without knowing how doable this is, mind you - would be support for an additional list layer for the event window and its related UI.
The episode I'm working on is very large in scope with many new objects added, and in the end I have every intention to not lock out a level from using the original behavior of an object (etc.) next to the additional one that uses its ID. Example: see how much food I'm adding in the demo levels. You might think no one in their right mind would use more than 255 different food items in a single level, and yes, that's definitely reasonable. But the logical, clean-looking and conveniently usable end goal would be to have the same object asc for all the episode levels, similarly to BL18 or HH24. Even at this very moment there's 92 already, that's over 1/3 of all the event IDs available. Imagine if MLLE supported branching out events further so that the selection list could go, for example...
(I sure hope this displays in a readable manner...) You might suggest that there's already a solution in that I can use event parameters to introduce an additional layer of selection, but here's the thing: it's not quite as readable in MLLE's level view. The squares are limited to the event name, and the parameter is only a small piece of text on the bottom bar - and that's a generic number for anything custom-made. It'd be far more readable if the event display could read what it should say from a label one layer deeper than the event ID name. And an innate support for keeping the original object behavior there as an option from the built-in custom object editor would surely be more inviting for script newbies. Even having done this for a good while now, the logistics of deciding which objects can I overwrite since I won't be using them can be a pain in the butt.
__________________
my stuff |
![]() |
«
Previous Thread
|
Next Thread
»
| Thread Tools | |
|
|
All times are GMT -8. The time now is 01:22 PM.
Jazz2Online © 1999-INFINITY (Site Credits). Jazz Jackrabbit, Jazz Jackrabbit 2, Jazz Jackrabbit Advance and all related trademarks and media are ™ and © Epic Games. Lori Jackrabbit is © Dean Dodrill. J2O development powered by Loops of Fury and Chemical Beats. Powered by vBulletin® Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Original site design by Ovi Demetrian. DrJones is the puppet master. Eat your lima beans, Johnny.






