• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Player Loads TRansport-> Fill Transport With Most Expensive Units

Status
Not open for further replies.
Level 6
Joined
Sep 19, 2005
Messages
169
Could someone write this script for me? Also, in my game their point value is set to their gold cost. It would be nice that even if a transport is full, that if a player clicked to load unit x and unit x was more expensive than unit y, it would take unit y's spot in the transport. You would get credit and I would implement the code and release a new version of the map on bnet right away.

StatusEvents is already used in my map, this would probably be useful.

JASS:
library StatusEvents requires AutoIndex
//===========================================================================
// Information:
//==============
//
//     StatusEvents is an add-on library for AutoIndex. It gives you events that
// detect the following things: when units resurrect, when units are raised with
// Animate Dead, when units begin reincarnating, when units finish reincarnating,
// when transports load units, and when transports unload units. It also provides
// other useful functions: you can check if a unit is currently raised with Ani-
// mate Dead, get the transport carrying a unit, get the number of a units in a
// transport, get the passenger in a specific slot of a transport, and enumerate
// through all of the units in a transport.
//
//===========================================================================
// How to use StatusEvents:
//==========================
//
//     You can use the events in this library to run specific functions when
// an event occurs. Unit-related events require a function matching the Stat-
// usEvent function interface, and transport-related events require a function
// matching the TransportEvent function interface:
//
// function interface StatusEvent takes unit u returns nothing
// function interface TransportEvent takes unit transport, unit passenger returns nothing
//
//     The following examples use the StatusEvents function interface:
//
// function UnitDies takes unit u returns nothing
//     call BJDebugMsg(GetUnitName(u)+" has died.")
// endfunction
//
// function UnitResurrects takes unit u returns nothing
//     call BJDebugMsg(GetUnitName(u)+" has been resurrected.")
// endfunction
//
// function Init takes nothing returns nothing
//     call OnUnitDeath(UnitDies)
//     call OnUnitResurrect(UnitResurrects)
// endfunction
//
//     And the following examples use the TransportEvents function interface:
//
// function UnitLoads takes unit transport, unit passenger returns nothing
//     call BJDebugMsg(GetUnitName(transport)+" loaded +"GetUnitName(passenger))
// endfunction
//
// function UnitUnloads takes unit transport, unit passenger returns nothing
//     call BJDebugMsg(GetUnitName(transport)+" unloaded +"GetUnitName(passenger))
// endfunction
//
// function Init takes nothing returns nothing
//     call OnUnitLoad(UnitLoads)
//     call OnUnitUnload(UnitUnloads)
// endfunction
//
//     Here is an example of using ForPassengers to enumerate each unit in
// a transport and heal them for 100 life:
//
// function HealPassenger takes unit transport, unit passenger returns nothing
//     call SetWidgetLife(passenger, GetWidgetLife(passenger) + 100.)
// endfunction
// function HealAllPassengers takes unit transport returns nothing
//     call ForPassengers(transport, HealPassenger)
// endfunction
//
//     GetPassengerBySlot provides an alternative way to enumerate the
// units within a transport. (The following example would heal a unit
// that occupies multiple slots in the transport only one time, since
// GetPassengerBySlot assumes that each unit occupies only one slot.)
//
// function HealAllPassengers takes unit transport returns nothing
//     local integer slot = 1 //Start at slot 1.
//     local unit passenger
//         loop
//             set passenger = GetPassengerBySlot(transport, slot)
//             exitwhen passenger == null
//             SetWidgetLife(passenger, GetWidgetLife(passenger) + 100.)
//             set slot = slot + 1
//         endloop
// endfunction
//
//===========================================================================
// StatusEvents API:
//===================
//
// OnUnitDeath(StatusEvent)
//   This event runs when any unit dies. It fires after the unit is dead, but
//   before any death triggers fire.
//
// OnUnitResurrect(StatusEvent)
//   This event runs when any unit is resurrected. It also fires when units
//   are raised with Animate Dead or Reincarnation, as those are forms of
//   resurrection as well.
//
// OnUnitAnimateDead(StatusEvent)
//   This event runs when any unit is raised with Animate Dead. It fires after
//   the resurrection event.
//
// IsUnitAnimateDead(unit) -> boolean
//   This function returns a boolean that indicates if the specified unit
//   has been raised with Animate Dead.
//
// OnUnitReincarnateStart(StatusEvent)
//   This event runs when any unit begins reincarnating. The OnUnitDeath event
//   will run first.
//
// OnUnitReincarnateEnd(StatusEvent)
//   This event runs when any unit finishes reincarnating. The OnUnitResurrect
//   event will occur immediately after.
//
// OnUnitLoad(TransportEvent)
//   This event runs when any transport loads a passenger.        
//
// OnUnitUnload(TransportEvent)
//   This event runs when any transport unloads a passenger.
//
// GetUnitTransport(unit)
//   Returns the transport that a unit is loaded in. Returns null if the
//   unit is not riding in any transport.
//
// CountPassengers(transport) -> integer
//   Returns the number of passengers in the specified transport.
//
// GetPassengerBySlot(transport, slot) -> unit
//   Returns the passenger in the given slot of the specified transport.
//   However, if a unit takes  more than one transport slot, it will only be
//   treated as occupying one transport slot.
//
// ForPassengers(transport, TransportEvent)
//   This function runs a TransportEvent immediately for each passenger in
//   the specified transport.
//
//===========================================================================

function interface StatusEvent takes unit u returns nothing

function IsUnitAnimateDead takes unit u returns boolean
    return AutoIndex.isUnitAnimateDead(u)
endfunction

//===========================================================================

//! textmacro RunStatusEvent takes EVENT
    set n = 0
    loop
        exitwhen n > $EVENT$funcs_n
        call $EVENT$funcs[n].evaluate(u)
        set n = n + 1
    endloop
//! endtextmacro

//Injecting this textmacro into AutoIndex will cause the events to actually run.

//===========================================================================

//! textmacro StatusEvent takes EVENT, EVENTTYPE
    globals
        $EVENTTYPE$ array $EVENT$funcs
        integer $EVENT$funcs_n = -1
    endglobals
    function OnUnit$EVENT$ takes $EVENTTYPE$ func returns nothing
        set $EVENT$funcs_n = $EVENT$funcs_n + 1
        set $EVENT$funcs[$EVENT$funcs_n] = func
    endfunction
//! endtextmacro

//Instantiate the function to register events of each type.
//! runtextmacro StatusEvent("Death", "StatusEvent")
//! runtextmacro StatusEvent("Resurrect", "StatusEvent")
//! runtextmacro StatusEvent("AnimateDead", "StatusEvent")

//===========================================================================
//The code below this point adds Reincarnation support to StatusEvents.
//Credit to ToukoAozaki for the idea behind this detection method.

//! runtextmacro StatusEvent("ReincarnationStart", "StatusEvent")
//! runtextmacro StatusEvent("ReincarnationFinish", "StatusEvent")
//Create registration functions for reincarnation start and stop events.

globals
    private timer ReincarnateTimer = CreateTimer()
    private boolean array Reincarnated
    private unit array Reincarnating
    private integer Reincarnating_N = -1
endglobals

private function OnResurrect takes unit u returns nothing
    local integer index = GetUnitId(u)
    local integer n
        if Reincarnated[index] then
            set Reincarnated[index] = false
            //If a resurrecting unit is flagged as reincarnating,
            //it's time to run the ReincarnationFinish event.
            //! runtextmacro RunStatusEvent("ReincarnationFinish")
        endif
endfunction

private function ReincarnateCheck takes nothing returns nothing
    local integer n = Reincarnating_N
    local unit u
        loop
            exitwhen n < 0
            set u = Reincarnating[n]
            if IsUnitIndexed(u) and Reincarnated[GetUnitId(u)] then
                //If the unit is still flagged as reincarnating, it means DeathDetect didn't run.
                //The unit is actually reincarnating, so run the ReincarnationStart event.
                //! runtextmacro RunStatusEvent("ReincarnationStart")
            endif
            set Reincarnating[n] = null
            set n = n - 1
        endloop
        set Reincarnating_N = -1
    set u = null
endfunction

private function OnDeath takes unit u returns nothing
    set Reincarnated[GetUnitId(u)] = true
    //Assume any unit that dies is going to reincarnate, unless this
    //flag is set to false later by the DeathDetect function.
    set Reincarnating_N = Reincarnating_N + 1 //Add the dying unit to a stack and 
    set Reincarnating[Reincarnating_N] = u    //check the flag 0. seconds later.
    call TimerStart(ReincarnateTimer, 0., false, function ReincarnateCheck)
endfunction
    
private function DeathDetect takes nothing returns boolean
        set Reincarnated[GetUnitId(GetTriggerUnit())] = false
    return false //Set the Reincarnated flag to false if the unit will not reincarnate.
endfunction

private function OnEnter takes unit u returns nothing
    set Reincarnated[GetUnitId(u)] = false
    //When a unit enters the map, initialize its Reincarnated flag to false.
endfunction
    
private struct ReincarnationInit extends array
    private static method onInit takes nothing returns nothing
        local trigger deathdetect = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(deathdetect, EVENT_PLAYER_UNIT_DEATH)
            call TriggerAddCondition(deathdetect, function DeathDetect)
            //This trigger runs 0. seconds after OnUnitDeath events, 
            //but does not fire if the unit is going to Reincarnate.
            call OnUnitIndexed(OnEnter)
            call OnUnitDeath(OnDeath)
            call OnUnitResurrect(OnResurrect)
    endmethod
endstruct

//===========================================================================
//All of the remaining code deals with transports.

function interface TransportEvent takes unit transport, unit passenger returns nothing

function GetUnitTransport takes unit u returns unit
    return Transport.getUnitTransport(u)
endfunction
function CountPassengers takes unit transport returns integer
    return Transport.countPassengers(transport)
endfunction
function GetPassengerBySlot takes unit transport, integer slot returns unit
    return Transport.getPassengerBySlot(transport, slot)
endfunction
function ForPassengers takes unit transport, TransportEvent func returns nothing
    call Transport.forPassengers(transport, func)
endfunction

//===========================================================================

//! runtextmacro StatusEvent("Load", "TransportEvent")
//! runtextmacro StatusEvent("Unload", "TransportEvent")
//Create registration functions for load and unload events.

//! textmacro TransportUnloadCheck
    if GetIssuedOrderId() == 851972 and Transport.loadedin[GetUnitId(GetTriggerUnit())] != null then
        call Transport.unloadUnit(GetTriggerUnit())
    endif
//! endtextmacro
//If the unit recieves a stop order while loaded in a transport, it was unloaded.
//! textmacro TransportUnload
    if Transport.loadedin[index] != null then
        call Transport.unloadUnit(u)
    endif
//! endtextmacro
//! textmacro TransportClean
    if Transport.transports[index] != 0 then
        call Transport.transports[index].destroy()
        set Transport.transports[index] = 0
    endif
//! endtextmacro
//Injecting these textmacros into AutoIndex will cause the events to actually run.

//! textmacro RunTransportEvent takes EVENT
    set n = 0
    loop
        exitwhen n > $EVENT$funcs_n
        call $EVENT$funcs[n].evaluate(transport, passenger)
        set n = n + 1
    endloop
//! endtextmacro
//The above textmacro is used to run the Load/Unload events in the Transport struct below.

//===========================================================================
//A transport struct is created and attached to any unit detected loading another unit.
//It keeps track of the units within a transport and updates when they load or unload.

struct Transport
            static Transport array transports
            static unit array loadedin
    private static integer array loadedindex
    private static group array groups
    private static integer groups_n = -1
    
    private unit array loaded[10] //Transports can only carry 10 units.
    private integer loaded_n = -1
    
    //===========================================================================
    
    static method getUnitTransport takes unit u returns unit
        return loadedin[GetUnitId(u)]
    endmethod
    
    static method countPassengers takes unit transport returns integer
        return transports[GetUnitId(transport)].loaded_n + 1
    endmethod
    
    //===========================================================================
    
    static method getPassengerBySlot takes unit transport, integer slot returns unit
            if slot < 1 or slot > 10 then
                return null
            endif
        return transports[GetUnitId(transport)].loaded[slot - 1]
    endmethod
    
    static method forPassengers takes unit transport, TransportEvent func returns nothing
        local Transport this = transports[GetUnitId(transport)]
        local integer n = 0
            if loaded_n == -1 then
                return //Return if transport has no units loaded inside.
            endif
            loop
                exitwhen n > loaded_n
                call func.evaluate(transport, loaded[n])
                //Loop through each passenger and call the TransportEvent func on it.
                set n = n + 1
            endloop
    endmethod
    
    //===========================================================================

    static method loadUnit takes unit transport, unit passenger returns nothing
        local Transport this = transports[GetUnitId(transport)]
        local integer n
            if this == 0 then   //If this is the first time this transport has loaded a unit...
                set this = allocate()                         //allocate a Transport struct,
                set transports[GetUnitId(transport)] = this   //and attach it to the unit.
            endif
            set loaded_n = loaded_n + 1      //Increment the passenger counter.
            set loaded[loaded_n] = passenger //Put the passenger in the unit array.
            set loadedindex[GetUnitId(passenger)] = loaded_n //Attach the index to the passenger.
            set loadedin[GetUnitId(passenger)] = transport   //Attach the transport struct to the transport.
            //! runtextmacro RunTransportEvent("Load")
    endmethod //Run the OnUnitLoad events.
    
    static method unloadUnit takes unit passenger returns nothing
        local unit transport = GetUnitTransport(passenger)      //Get the transport unit.
        local Transport this = transports[GetUnitId(transport)] //Get the transport struct.
        local integer n = loadedindex[GetUnitId(passenger)]     //Get the passenger's index.
            loop
                exitwhen n == loaded_n
                set loaded[n] = loaded[n + 1]
                set loadedindex[GetUnitId(loaded[n])] = n
                set n = n + 1 //Starting from the position of the removed unit,
            endloop           //shift everything down by one and update the index.
            set loaded[n] = null
            set loaded_n = loaded_n - 1          //Decrement the passenger counter.
            set loadedin[GetUnitId(passenger)] = null //Null the unloaded unit's transport.
            //! runtextmacro RunTransportEvent("Unload")
        set transport = null //Run the OnUnitUnload events.
    endmethod
    
    //===========================================================================
    
    private static method load takes nothing returns boolean
            call loadUnit(GetTransportUnit(), GetTriggerUnit())
        return false //When a unit loads another unit, run the loadUnit method.
    endmethod
    
    private static method onInit takes nothing returns nothing
        local trigger load = CreateTrigger()
        local integer i = 15
            loop
                exitwhen i < 0
                call TriggerRegisterPlayerUnitEvent(load, Player(i), EVENT_PLAYER_UNIT_LOADED, function AutoIndex_UnitFilter)
                set i = i - 1
            endloop
            call TriggerAddCondition(load, function Transport.load)
            //AutoIndex will handle calling the unloadUnit method when necessary, so an unload trigger is not needed here.
            set Transport(0).loaded_n = -1 //Initialize this to -1 to make the CountUnitsInTransport
    endmethod                              //function work on null and non-transport units.
    
endstruct

endlibrary
 
Status
Not open for further replies.
Top