Knuckle Cracker

Particle Fleet => Map Makers, Ship Builders, and Coders => Topic started by: kajacx on December 01, 2017, 07:06:54 PM

Title: [PRPL] Custom module/unit settings manager
Post by: kajacx on December 01, 2017, 07:06:54 PM
A long time ago, in a forum post far far away, there was a discussion about custom modules having settable options like normal modules have to (for example, turing them on/off, setting target priority, etc.). Since that is a good idea, I have made some PRPL that will allow mapmakers to register some customizable options for their custom ship modules or units with just a "few" lines of code.

How it works: (for the end player)

Screenshots



[close]

How to set it up: (for the mapmakers)
Once you get it up and running, adding new options is very easy. Here is a full list:

So, without furder ado, let's see some examples of how to register, read and manually set your settings:

Example 1: Simple yes/no option


once
    #create the option and color lists
    CreateList ->options
    CreateList ->colors

    <-options "On" AppendToList #Index 0
    <-colors 0 AppendToList #R
    <-colors 255 AppendToList #G
    <-colors 0 AppendToList #B

    <-options "Off" AppendToList #Index 1
    <-colors 255 AppendToList #R
    <-colors 0 AppendToList #G
    <-colors 0 AppendToList #B
   
    Self "Active" <-options <-colors @CmmApiRegisterModuleAndShip
endonce

"Is active:" @IsActive Trace2
28 Delay

:IsActive
    Self "Active" @CmmApiGetShipModuleOption not
    # returns index (0="On", 1="Off") so we need to negate
   
# ---- The 3 functions from the API ----
:CmmApiSetShipModuleOption # [ sid name int - ]
    ->cassmo_value
    concat "ModuleOption" swap concat #varname
    -1 "IsCustomModuleManager" 1 GetCoresWithVar 0 do max loop asint swap #uid varname
    "CustomModuleManager.prpl" swap #uid scriptName varname
    <-cassmo_value SetScriptVar # -

:CmmApiGetShipModuleOption # [ sid name - int ]
    concat "ModuleOption" swap concat #varname
    -1 "IsCustomModuleManager" 1 GetCoresWithVar 0 do max loop asint swap #uid varname
    "CustomModuleManager.prpl" swap #uid scriptName varname
    GetScriptVar #selected option

:CmmApiRegisterModuleAndShip # [ sid name list list - ]
    ->carmas_colors
    ->carmas_options
    ->carmas_name
    ->carmas_sid
   
    "IsCustomModuleManager" 1 GetCoresWithVar 0 do ->carmas_manager loop
   
    #set the options and colors for that module
    <-carmas_manager "CustomModuleManager.prpl" "ModuleOptions" <-carmas_name concat <-carmas_options SetScriptVar
    <-carmas_manager "CustomModuleManager.prpl" "ModuleColors" <-carmas_name concat <-carmas_colors SetScriptVar
   
    #create a module list for this ship if not yet set
    <-carmas_manager "CustomModuleManager.prpl" "ModuleShip" <-carmas_sid concat GetScriptVar ->carmas_moduleList
    <-carmas_moduleList GetType "LIST" neq if
        CreateList ->carmas_moduleList
        <-carmas_manager "CustomModuleManager.prpl" "ModuleShip" <-carmas_sid concat <-carmas_moduleList SetScriptVar
    endif
   
    #register the module to this ship, if not already registered
    0 #contains
    <-carmas_moduleList GetListCount 0 do
        <-carmas_moduleList[I] <-carmas_name eq or
    loop not if
        <-carmas_moduleList <-carmas_name AppendToList
    endif
   
    #initilize the option to 0
    <-carmas_manager "CustomModuleManager.prpl" "ModuleOption" <-carmas_sid concat <-carmas_name concat 0 SetScriptVar


As you can see, you need 4 things to register a custom option setting: the id of the ship/unit, the name of the setting, the list of the values and the list of colors for those values.

For reading the value, just specify the ID of the unit you wish to read and the name of the setting. I recommend writing a more friendly read function, like in the example. The default read function returns the index of the selected option. The first option (with index 0) is always default.
[close]

Example 2: More settings, manual set


once
    #register fire button
    CreateList ->fireOptions
    CreateList ->fireColors

    <-fireOptions "Fire" AppendToList
    <-fireColors 255 AppendToList #R
    <-fireColors 128 AppendToList #G
    <-fireColors 0 AppendToList #B

    <-fireOptions "Fire" AppendToList #the text can be the same, it's the index that matters
    <-fireColors 255 AppendToList #R
    <-fireColors 128 AppendToList #G
    <-fireColors 0 AppendToList #B
   
    Self "Action" <-fireOptions <-fireColors @CmmApiRegisterModuleAndShip
   
    #register target
    CreateList ->targetOptions
    CreateList ->targetColors

    <-targetOptions "Particles" AppendToList
    <-targetColors 255 AppendToList #R
    <-targetColors 0 AppendToList #G
    <-targetColors 64 AppendToList #B

    <-targetOptions "Ships" AppendToList
    <-targetColors 255 AppendToList #R
    <-targetColors 64 AppendToList #G
    <-targetColors 0 AppendToList #B
   
    <-targetOptions "Units" AppendToList
    <-targetColors 196 AppendToList #R
    <-targetColors 0 AppendToList #G
    <-targetColors 16 AppendToList #B
   
    Self "Target" <-targetOptions <-targetColors @CmmApiRegisterModuleAndShip
endonce

@IsFiring if
    "Firing at" @GetTarget Trace2
endif

:IsFiring
    Self "Action" @CmmApiGetShipModuleOption ->firing
    Self "Action" 0 @CmmApiSetShipModuleOption
    <-firing

:GetTarget
    <-targetOptions[Self "Target" @CmmApiGetShipModuleOption]

#I ommited the 3 API functions in other to save space, it's the same code anyway


Here we see 2 settings on one unit (see the 3rd screenshot). The idea is to first select a target, and then click the "Fire" button. Once the "Action" setting is set to the second "Fire" option (index 1), the script will fire at the "Target" (represented by just tracing "Firing at X"). This is a neat trict to create a clickable button rather than a settable option.
[close]

Example 3: A custom module


#showing only relevant portions of the code
once
    # ...

    CreateList ->convertorOptions
    CreateList ->convertorColors
   
    <-convertorOptions "Nearest" AppendToList
    <-convertorColors 0 AppendToList
    <-convertorColors 255 AppendToList
    <-convertorColors 0 AppendToList
   
    <-convertorOptions "Farest" AppendToList
    <-convertorColors 0 AppendToList
    <-convertorColors 255 AppendToList
    <-convertorColors 0 AppendToList
   
    <-convertorOptions "Random" AppendToList
    <-convertorColors 255 AppendToList
    <-convertorColors 196 AppendToList
    <-convertorColors 0 AppendToList
   
    <-convertorOptions "Off" AppendToList
    <-convertorColors 255 AppendToList
    <-convertorColors 0 AppendToList
    <-convertorColors 0 AppendToList
   
    <-sid "Convertor" <-convertorOptions <-convertorColors @CmmApiRegisterModuleAndShip
endonce

    # ...
    @GetConfig 3 neq and (<-cooldown 0 lte) if # is not disabled and cooldown ready
    # ...
            @Fire if
                 0 ->energy # reset energy
            endif
    # ...
    endif
    # ...


:Fire # [ - bool ]
    @SelectParticle ->pid
    <-pid -1 eq if #particle not found
        0 return
    endif
   
    #delete old particle
    <-pid GetParticlePosition ->py ->px
    <-pid GetParticleMotion ->my ->mx
    <-pid 1 DestroyParticle
   
    #create new particle
    <-px <-py 0 0 0 <-Enemy CreateParticle ->pid
    <-pid <-mx neg <-my neg SetParticleMotion
   
    1 #return success

:SelectParticle
    @GetConfig ->config
    CurrentCoords <-Range 0 <-Enemy not GetParticlesInRange ->particles
    <-particles GetListCount eq0 if
        -1 return #nothing found
    endif
   
    <-config 2 eq if #random
        <-particles[0 <-particles GetListCount RandInt] return #return random particle
    endif
   
    <-config 0 eq if #nearest
        1000000.0 ->distance
        -1 ->pid
        <-particles GetListCount 0 do
            CurrentPixelCoords <-particles[I] GetParticlePosition Distance ->dist
            <-dist <-distance lt if
                <-dist ->distance
                <-particles[I] ->pid
            endif
        loop
        <-pid return
    endif
   
    <-config 1 eq if #farest
        -1.0 ->distance
        -1 ->pid
        <-particles GetListCount 0 do
            CurrentPixelCoords <-particles[I] GetParticlePosition Distance ->dist
            <-dist <-distance gt if
                <-dist ->distance
                <-particles[I] ->pid
            endif
        loop
        <-pid return
    endif
   
    "Invalid config:" <-config Trace2
    -1 #return
   
:GetConfig
    <-sid "Convertor" @CmmApiGetShipModuleOption


Here I have a custom module that converts enemy particles to friendly. The "Fire" function will attempt to find a particle and convert it, returning true if it found and converted a particle, false otherwise. Note that the function is only called only if the module isn't disabled to begin with.

Also note how the custom module passes the ID of the ship into the registry and when reading the value, not the ID of the custom module itself.
[close]

By now you should be able to add some custom settings to your modules or units as well. Here are some final remarks:

That's about it, I'm looking forward to some maps with configurable units on the Exchange.