• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[JASS] Football Throw

Status
Not open for further replies.
Level 12
Joined
Aug 20, 2007
Messages
866
Ok, I triggered up this script, but I'm not sure how I could make it MUI
Btw, the parabolic formula is based off of distance + height (the height is also based off the distance, so it's just distance)

JASS:
//Conditions
function StartThrow_Condit takes nothing returns boolean
    if GetSpellAbilityId() == 'A001' then
      return true
    endif
    return false
endfunction

//Functions
function Movement takes nothing returns nothing
    local real oldx = GetUnitX(udg_Ball)
    local real oldy = GetUnitY(udg_Ball)
    local effect bang
    local real newheight = 0.0
    set udg_PolarX = udg_PolarX + udg_MoveInterval
    call SetUnitPosition(udg_Ball, oldx + udg_Cos * udg_MoveInterval, oldy + udg_Sin * udg_MoveInterval)
    set newheight = (udg_A * udg_PolarX * udg_PolarX) - (udg_B * udg_PolarX)
    call SetUnitFlyHeight(udg_Ball, newheight, 10000)
    if newheight < 0.0 then
      call ShowUnit(udg_Ball, false)
      set bang = AddSpecialEffect("Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl",GetUnitX(udg_Ball),GetUnitY(udg_Ball))
      call DestroyEffect(bang)
      call KillUnit(udg_Ball)
      set udg_Ball = null
      set bang = null
      set udg_A = 0.0
      set udg_B = 0.0
      set udg_Cos = 0.0
      set udg_Sin = 0.0
      set udg_PolarX = 0.0
      set udg_MoveInterval = 0.0
      set udg_MaxHeight = 0.0
      set udg_Distance = 0.0
    endif
endfunction

function StartThrow takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local real x1 = GetUnitX(u)
    local real y1 = GetUnitY(u)
    local location loc = GetSpellTargetLoc()
    local real x2 = GetLocationX(loc)
    local real y2 = GetLocationY(loc)
    local timer t = CreateTimer()
    local real radians = Atan2(y2 - y1 , x2 - x1)
    set udg_Distance = SquareRoot((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1))
    set udg_Cos = Cos(radians)
    set udg_Sin = Sin(radians)
    set udg_MoveInterval = 10 + udg_Distance/75
    set udg_PolarX = 0
    set udg_MaxHeight = udg_Distance * .666 + 300
    set udg_A = (-4 * udg_MaxHeight) / (udg_Distance * udg_Distance)
    set udg_B = udg_Distance * udg_A
    set udg_Ball = CreateUnit(GetOwningPlayer(u), 'h000', x1, y1, bj_RADTODEG * radians)
    call RemoveLocation(loc)
    set loc = null
    call TimerStart(t, .035, true, function Movement)
    call TriggerSleepAction(udg_Distance/udg_MoveInterval * .035)
    call DestroyTimer(t)
    set u = null
    set t = null
endfunction

function InitTrig_Football_Throw takes nothing returns nothing
   local integer i = -1
   local trigger t = CreateTrigger()

   //Add Actions
   call TriggerAddAction(t, function StartThrow)

   //Add Conditions
   call TriggerAddCondition(t, Condition( function StartThrow_Condit))

   //Loops
   loop
     set i=i+1
     exitwhen i==12

     //Events (Looped)
     call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_CAST, null)

    endloop
endfunction


If somebody could show me an example of how to make this MUI, that would be great

The things that I've picked up on so far to connect the handler func to the timer is:

-Attacheable Variables
-"Local Handle Variables" (not sure the difference)
-Game Cache

I plan to use global variables, I just want to get an integer out of the expired timer (put the integer into the arrays)

Also, if somebody could show me how to properly do the "Damage Area" function, that would be great (it won't show up in my JassCraft for some reason)
 
Level 12
Joined
Aug 20, 2007
Messages
866
Revision

Woot, I implemented a piece of Kattana's system, I'd like to make the system more efficient without using the gamecache, but I don't know how

Here's the new code

JASS:
//Taken from Kattana's Local Vars() system, only using the int
function H2I takes handle h returns integer
    return h
    return 0
endfunction

function LocalVars takes nothing returns gamecache
    return InitGameCache("jasslocalvars.w3v")
endfunction

function SetHandleInt takes handle subject, string name, integer value returns nothing
    if value==0 then
        call FlushStoredInteger(LocalVars(),I2S(H2I(subject)),name)
    else
        call StoreInteger(LocalVars(), I2S(H2I(subject)), name, value)
    endif
endfunction

function GetHandleInt takes handle subject, string name returns integer
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
endfunction
 
function FlushHandleLocals takes handle subject returns nothing
    call FlushStoredMission(LocalVars(), I2S(H2I(subject)) )
endfunction

//============================================================
//Conditions
function StartThrow_Condit takes nothing returns boolean
    if GetSpellAbilityId() == 'A001' then
      return true
    endif
    return false
endfunction

//Functions
function Movement takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer index = GetHandleInt(t,"index")
    local real oldx = GetUnitX(udg_Ball[index])
    local real oldy = GetUnitY(udg_Ball[index])
    //local effect bang
    local real newheight = 0.0
    set udg_PolarX[index] = udg_PolarX[index] + udg_MoveInterval[index]
    call SetUnitPosition(udg_Ball[index], oldx + udg_Cos[index] * udg_MoveInterval[index], oldy + udg_Sin[index] * udg_MoveInterval[index])
    set newheight = (udg_A[index] * udg_PolarX[index] * udg_PolarX[index]) - (udg_B[index] * udg_PolarX[index])
    call SetUnitFlyHeight(udg_Ball[index], newheight, 10000)
    if newheight <= 0.0 then
      call ShowUnit(udg_Ball[index], false)
      //set bang = AddSpecialEffect("Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl",GetUnitX(udg_Ball[index]),GetUnitY(udg_Ball[index]))
      //call DestroyEffect(bang)
      call KillUnit(udg_Ball[index])
      set udg_Ball[index] = null
      //set bang = null
      set udg_A[index] = 0
      set udg_B[index] = 0
      set udg_Cos[index] = 0
      set udg_Sin[index] = 0
      set udg_PolarX[index] = 0
      set udg_MaxHeight[index] = 0
      set udg_MoveInterval[index] = 0
      call FlushHandleLocals(t)
      call PauseTimer(t)
      call DestroyTimer(t)
    endif
endfunction

function StartThrow takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local real x1 = GetUnitX(u)
    local real y1 = GetUnitY(u)
    local location loc = GetSpellTargetLoc()
    local real x2 = GetLocationX(loc)
    local real y2 = GetLocationY(loc)
    local timer t = CreateTimer()
    local real radians = Atan2(y2 - y1 , x2 - x1)
    local real distance = SquareRoot((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1))
    
    //sets the index
    if udg_Index < 1000 then
      set udg_Index = udg_Index + 1
    else
      set udg_Index = 1
    endif
    
    //adds the integer to the timer
    call SetHandleInt(t, "index", udg_Index)

    //sets all the variables that will be used during movement
    set udg_Cos[udg_Index] = Cos(radians)
    set udg_Sin[udg_Index] = Sin(radians)
    set udg_MoveInterval[udg_Index] = 2 + distance/50
    set udg_PolarX[udg_Index] = 0
    set udg_MaxHeight[udg_Index] = distance * .1 + 600
    set udg_A[udg_Index] = (-4 * udg_MaxHeight[udg_Index]) / (distance * distance)
    set udg_B[udg_Index] = distance * udg_A[udg_Index]
    set udg_Ball[udg_Index] = CreateUnit(GetOwningPlayer(u), 'h000', x1, y1, bj_RADTODEG * radians)
    //Destroy the location
    call RemoveLocation(loc)
    set loc = null

    call TimerStart(t, .04, true, function Movement)
    call TriggerSleepAction(distance/udg_MoveInterval[udg_Index] * .04 + 1)
    set u = null
    set t = null
endfunction

function InitTrig_Football_Throw takes nothing returns nothing
   local integer i = -1
   local trigger t = CreateTrigger()

   //Add Actions
   call TriggerAddAction(t, function StartThrow)

   //Add Conditions
   call TriggerAddCondition(t, Condition( function StartThrow_Condit))

   //Loops
   loop
     set i=i+1
     exitwhen i==12

     //Events (Looped)
     call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_CAST, null)

    endloop
endfunction


It works great, if there are any suggestions on how to make it without using a gamecache, that'd be awesome
 
Level 10
Joined
Jun 26, 2005
Messages
236
Try this, requires newgen and Grim001's data system:
Make sure the trigger you copy it into is called 'ThrowBall' or it won't work.

JASS:
scope ThrowBall
//text macro using data system, allows me to 'pass' the struct to another function later on, eg, 'local Data data=GetThrowBall(t)'
//! runtextmacro DataDeclare("ThrowBall","integer")    
  private struct Data
      unit Ball
      real PolarX
      real a
      real b
      real cos
      real sin
      real MoveInterval
      real MaxHeight
      real Distance
  endstruct
    
    private function Check takes nothing returns boolean
        return GetSpellAbilityId()=='A001'
    endfunction

    private function Movement takes nothing returns nothing
        local timer t=GetExpiredTimer()
        
        //Attach struct to the expired timer
        local Data data=GetThrowBall(t)
        
        local real oldx=GetUnitX(data.Ball)
        local real oldy=GetUnitY(data.Ball)
        local effect bang
        local real newheight=0.
    
        set data.PolarX=data.PolarX+data.MoveInterval
        call SetUnitPosition(data.Ball,oldx+data.cos*data.MoveInterval,oldy+data.sin*data.MoveInterval)
        set newheight = (data.a*data.PolarX*data.PolarX)-(data.b*data.PolarX)
        call SetUnitFlyHeight(data.Ball,newheight,10000)
    
         if newheight<0.0 then
           call ShowUnit(data.Ball,false)
           set bang=AddSpecialEffect("Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl",GetUnitX(data.Ball),GetUnitY(data.Ball))
           call DestroyEffect(bang)
           call KillUnit(data.Ball)
           call DestroyTimer(t)
           
           //Destroy struct to remove leak
           call data.destroy()
           
           set t=null
         endif
    endfunction

    private function Start takes nothing returns nothing
        //Create an instance of the struct
        local Data data=Data.create()
        
        local unit u=GetTriggerUnit()
        local real x1=GetUnitX(u)
        local real y1=GetUnitY(u)
        local location loc=GetSpellTargetLoc()
        local real x2=GetLocationX(loc)
        local real y2=GetLocationY(loc)
        local timer t=CreateTimer()
        local real radians=Atan2(y2-y1,x2-x1)
    
        set data.Distance=SquareRoot((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))
        set data.cos=Cos(radians)
        set data.sin=Sin(radians)
        set data.MoveInterval=10+data.Distance/75
        set data.PolarX=0
        set data.MaxHeight=data.Distance*.666+300
        set data.a=(-4*data.MaxHeight)/(data.Distance*data.Distance)
        set data.b=data.Distance*data.a
        set data.Ball=CreateUnit(GetOwningPlayer(u),'h000',x1,y1,bj_RADTODEG*radians)
    
        call RemoveLocation(loc)
        set loc=null
        call TimerStart(t,.035,true,function Movement)
        call TriggerSleepAction(data.Distance/data.MoveInterval*.035)
        call DestroyTimer(t)
        set u=null
        set t=null
    endfunction

    public function InitTrig takes nothing returns nothing
        local integer i=0
        local trigger t=CreateTrigger()

        call TriggerAddAction(t,function Start)
        call TriggerAddCondition(t,Condition(function Check))

        loop
            call TriggerRegisterPlayerUnitEvent(t,Player(i),EVENT_PLAYER_UNIT_SPELL_CAST,null)
            set i=i+1
            exitwhen i==bj_MAX_PLAYER_SLOTS
        endloop
    endfunction
endscope

Data System:

JASS:
library DataSystem
function DS_H2I takes handle h returns integer
    return h
    return 0
endfunction

//! textmacro DataDeclare takes NAME, TYPE
globals
    $TYPE$ array $NAME$1
    $TYPE$ array $NAME$2
    $TYPE$ array $NAME$3
endglobals

function Set$NAME$ takes handle h, $TYPE$ v returns nothing
    local integer i = DS_H2I(h) - 0x100000
    if (i < 8191) then
        set $NAME$1[i] = v
    elseif (i < 16382) then
        set $NAME$2[i - 8191] = v
    elseif (i < 24573) then
        set $NAME$3[i - 16382] = v
    else
        call BJDebugMsg("Data System Error: Set$NAME$ handle index too high")
    endif
endfunction

function Get$NAME$ takes handle h returns $TYPE$
    local integer i = DS_H2I(h) - 0x100000
    if (i < 8191) then
        return $NAME$1[i]
    elseif (i < 16382) then
        return $NAME$2[i - 8191]
    elseif (i >= 24573) then
        call BJDebugMsg("Data System Error: Get$NAME$ handle index too high")
    endif
    return $NAME$3[i - 16382]
endfunction
//! endtextmacro
endlibrary
 
Last edited:
Level 12
Joined
Aug 20, 2007
Messages
866
Woah

+rep!!!

I thank you greatly
I recently dled a copy of NewGen, cept I don't understand how pretty much everything works

I do understand the structs though, that's not too difficult

Could you explain to me the part about the data library?
 
Level 12
Joined
Aug 20, 2007
Messages
866
ohh

Yeah that bit I didn't know

Could you help me out and explain how to create a struct and then use it in other functions?

Like a comment on each line of code for the function you wrote up
 
Level 12
Joined
Aug 20, 2007
Messages
866
Oh

Yeah I don't have a clue what text macros are

The other thing that was confusing me, was the stuff in the library, its got like

JASS:
function Set$NAME$ takes handle h, $TYPE$ v returns nothing
    local integer i = DS_H2I(h) - 0x100000
    if (i < 8191) then
        set $NAME$1[i] = v
    elseif (i < 16382) then
        set $NAME$2[i - 8191] = v
    elseif (i < 24573) then
        set $NAME$3[i - 16382] = v
    else
        call BJDebugMsg("Data System Error: Set$NAME$ handle index too high")
    endif
endfunction
function Get$NAME$ takes handle h returns $TYPE$
    local integer i = DS_H2I(h) - 0x100000
    if (i < 8191) then
        return $NAME$1[i]
    elseif (i < 16382) then
        return $NAME$2[i - 8191]
    elseif (i >= 24573) then
        call BJDebugMsg("Data System Error: Get$NAME$ handle index too high")
    endif
    return $NAME$3[i - 16382]
endfunction

I just learned (like an hour ago) how Kattana's Vars system works, but that stuff looks like gibberish to me, could you explain it?

If its too much to ask thats ok
 
Level 11
Joined
Feb 18, 2004
Messages
394
A text macro is esentally a preprocessor function. You declare a text macro with:
JASS:
//! textmacro Name takes ARGUMENT, OTHER_ARGUMENT
    // Content of the macro
//!endtextmacro

You can then run ('call') a text macro with the syntax:
JASS:
//! runtextmacro Name("Value 1", "Value 2")

When a text macro is run, any occurrences of $ARGUMENT_NAME$ will be replaced by the supplied value. (the $ signs are needed only in the body of the text macro, not in the //! textmacro line itself.)


As for DataSystem:

Data system allows you to relate a value to that of a handle's value. (Handle type variables are pointers.) This allows you to say, pass data to the callback of a timer started with TimerStart(). Normally, there is no way to pass data to the timer's callback. However, if you can 'attach' the data you wish to pass to the callback to the value of the timer handle, then you can use GetExpiredTimer() in the callback. You then have the value you attached the data to, and all you have to do is retrieve it.

Lets look at the code in a diffrent way:
JASS:
// Lets say you have this line in your spell's script:
//! runtextmacro DataDeclare("Data","integer")
// After you save, and before vJASS code is compiled down to normal JASS, that line will be replaced by:
globals
    integer array Data1
    integer array Data2
    integer array Data3
endglobals

function SetData takes handle h, integer v returns nothing
    local integer i = DS_H2I(h) - 0x100000
    if (i < 8191) then
        set Data1[i] = v
    elseif (i < 16382) then
        set Data2[i - 8191] = v
    elseif (i < 24573) then
        set Data3[i - 16382] = v
    else
        call BJDebugMsg("Data System Error: SetData handle index too high")
    endif
endfunction

function GetData takes handle h returns integer
    local integer i = DS_H2I(h) - 0x100000
    if (i < 8191) then
        return Data1[i]
    elseif (i < 16382) then
        return Data2[i - 8191]
    elseif (i >= 24573) then
        call BJDebugMsg("Data System Error: GetData handle index too high")
    endif
    return Data3[i - 16382]
endfunction

This gives you two functions: SetData() and GetData(). (Data being the first argument ($NAME$) given to the text macro)

SetData() takes a handle, and an integer. (integer being the second argument ($TYPE$) we passed to the text macro) First, it sets a variable:
JASS:
local integer i = DS_H2I(h) - 0x100000
The value is the integer value of the handle pointer, minus a really big hexidecimal number. The reason for that is twofold: All normally allocated handles have a value above 0x100000; and arrays in JASS can only have 8191 things in them. So one could do:
JASS:
set MyArrayVariable[H2I(SomeUnit) - 0x100000] = SomeValue
And generally, it would work. However, if you have a lot of memory leaks or forget to reduce the reference counter (Or if your map just has a lot of units and destructables and such) the value of H2I(SomeHandle) - 0x100000 may be over 8191. This would be very bad if you're just tossing the value in an array.

For this reason, three arrays are used in data system. If the value is under 8191, it uses the first array. If the value is under 16382, it uses the second. (subtracting 8191 from the value so that it is under 8191) If its under 24573, then it uses the third array. (again, subtracting the ammount it is over 1819 by.) This means it will work perfectly fine if your map has less than 8191*3 handles. (24573 handles)

Hope this explains enough.
 
Last edited:
Level 12
Joined
Aug 20, 2007
Messages
866
Ohhh

Thank you so much for that, explains a sh*tload

+ rep (like you really need it x) )

I got a hold of a NewGen manual (wasn' hard, just didn't think of it ><)
I'm gonna consult that before I ask any really vague questions here, although most of the custom systems I will still probably not have a clue

Btw, what is the limit for Warcraft to process handles? I would think if you've got 8191 handles, the game just won't function (I suppose that data system is for un-cleared structs???)
 
Level 12
Joined
Aug 20, 2007
Messages
866
DataSystem

I wanted to use that data system without NewGen, because I hate the NewGen, but I was wondering if it could work without being conjoined to structs, just handles straightforward. My problem is this

I *think* that the system uses structs, which get their handle integers a special way, while regular handles get their integers in a linear fashion (one after another), structs get them based on lowest integer available (or something like that), meaning that the 3 array system will only be exceeded if somebody never clears the struct data

I would like somebody to help me out with this, because I really have no idea how I can obtain this information
 
Status
Not open for further replies.
Top