Open noble-ux opened 4 years ago
Apologies for the delayed reply.
The list of objects available to Megalo is defined in the motl
tag on each *.map file. Compiled scripts refer to entries in that list by their numeric index within the list, notably not by the actual list item names. ReachVariantTool therefore has a hardcoded list that maps names (and in some cases, extra information like descriptions) to these numeric indices. Notably, it does not open *.map files and so does not care what names are used in the motl
tag (in fact, for several list items I chose to use different names because they were more intuitive).
As such:
If you want to make more objects available to Megalo, you must edit the motl
tag in the underlying *.map file.
If you want to use these modded objects in ReachVariantTool, you will have to use the name that ReachVariantTool expects you to use. For example, you can change the unused motl
entry for "Firebomb Grenade" to spawn traffic cones instead, and you could even change the name within the motl
tag, but you would still need to write firebomb_grenade
in ReachVariantTool to refer to traffic cones. (You could, however, put this at the top of your script: alias traffic_cone = firebomb_grenade
; then you can use traffic_cone
directly. You can also use the numeric index directly, but unfortunately, the documentation doesn't list those at present.)
It must also be noted that while it may be possible to extend the motl
list with new entries at its end, ReachVariantTool will reject numbers that are past the "official" list end. This is because invalid values will crash the game.
Addendum: I could in theory add a feature to allow people to override or replace the object type names for the compiler, but that would have to be opt-in on a per-script basis (rather than a program-wide setting) for the following reasons:
Changes to motl
that work for one script may break another script, if a script uses an object type name that has been changed.
Object type names are, internally, "imported names." Script types are allowed to "import" named values into the global scope. These values have to be always-accessible so that you can create aliases of them. This means that changing the object type name list could break a script by causing one of that script's existing alias names to conflict with the object type name.
We could set up OpcodeArgValueObjectType
to be able to hold a pointer to a DetailedEnum
to use as an override for the built-in one, and then have some kind of facility whereby you can define an object type list in a text file and we can load that into a DetailedEnum on request. (Perhaps it's time to add #pragma
s to the compiler?) We're somewhat fortunate in this regard in that OpcodeArgTypeinfo::imported_names
is a struct which holds a DetailedEnum
pointer: we can overwrite that if need be. (Actually, in that case, it'd be better for the logic for ObjectArgValueObjectType
to just refer to the imported_names
enum member directly.)
If I add this feature, I would need to validate names in the new list to enforce the usual rules against shadowing built-ins and keywords, with the additional caveat that I have to let you shadow built-ins that belong to OpcodeArgValueObjectType
because you're replacing its list of built-ins in the first place.
Ideal syntax, then, would probably be something like this with some syntax for the object names:
pragma replace_imported_names(_object_type):
imports/my_cool_map_objects.txt
end
Alternatively, we could allow this either inline in a script or in a secondary file:
pragma replace_imported_names(_object_type):
object_0
object_1
object_2
-- ...
end
And then we could allow imports of secondary files with another pragma (using paths relative to the application directory):
pragma import(imports/my_cool_map_objects.txt)
The overall syntax for pragma directives, then, would be:
pragma name -- no arguments or body
pragma name(arguments) -- no body
pragma name:
-- body
end
pragma name(arguments):
-- body
end
Additional considerations:
There would still be no way to redefine the object type list in contexts other than script compilation, e.g. the Required Object Types editor for gametype data.
Any types modified with the pragma
s described above would need to be reset after a compile operation is complete (or after it fails, is canceled, etc.). This requires the compiler to remember the original enums they used. (Maybe easier to just give OpcodeArgTypeinfo
a second imported_names
struct for overrides.)
If a script redefines a type's imported names multiple times, we need to ensure that we still restore the built-in name list properly after compiling.
The implementation described above would only allow the redefining of enums, not flags or other imported names. For the object type list, this isn't a problem, but the syntax and names chosen above imply broader functionality.
For object types, we need to make sure that a user-supplied enum does not contain more than 32767 imported names, as we use an int16_t to hold the value. Other types may have different maximum counts.
A syntax for overriding specific elements, rather than the whole list, will probably be more generally useful when dealing with object types, as might a syntax for extending the existing list. Mimicking the enum syntax might work (i.e. name = value) with the caveat that you have to be able to use old values' names e.g. "traffic_cone = firebomb_grenade" (so, the old names have to be "in scope" for the purposes of the override).
From my understanding the compiler checks objects in the script to a predefined list to grab it's tag location.
Is there any way for users to add on to this list or place other types of items that are not already predefined such as street_cone or even ff_plat_2x1_flat?
If not I wouldn't getting a list together of some objects and their tags if I could provide those to be added.