• 🏆 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!

[JASS] Total code meltdown

Status
Not open for further replies.
Level 2
Joined
Nov 8, 2012
Messages
7
Hi there everybody! I'm new to The Hive, just shipped over from The Helper. I don't think there's anyone left alive back there, so I though I'd try my luck here.

Now, my problem today is pretty big. I've coded an entire map, complete with it's own AI system and almost 100% JASS spells. The only problem is, when I put everything together, well, everything falls to pieces. I suspect either my coding method is COMPLETELY wrong, or I'm overloading the Warcraft Engine.

Here's a sample of my code: This is a very simple spell in which a unit fires a skillshot stun projectile. Some of the functions in there are some of my own custom functions. Pay particular attention to the structs, I suspect this may be what's wrong. EVERY JASS spell and system I have works on this single-timer array system.
JASS:
scope DemonCannon initializer init

private keyword CANNON

globals
    private constant integer ABILCODE = 'A00C'
    private constant integer DUMMY_ID = 'n001'
    private constant integer DUMMY_ABILCODE = 'A004'
    private constant real DAMAGE = 40
    private constant real SPEED = 1500
    private constant real RANGE = 1500
    private constant real IMPACT_SIZE = 150

    private integer I = 0
    private CANNON array DATA
    private timer TIMER = CreateTimer()
    private unit TempUnit = null
endglobals

private struct CANNON
    unit caster
    unit dummy
    real dX
    real dY
    real distance
    boolean terminate
    static thistype tempData
    
    static method create takes unit caster, real tX, real tY returns CANNON
        local CANNON a = CANNON.allocate()
        local real uX = GetUnitX(caster)
        local real uY = GetUnitY(caster)
        local real angle = Atan2((tY-uY),(tX-uX))
        
        set a.caster = caster
        set a.dummy = CreateUnit(NEUTRAL_PASSIVE,DUMMY_ID,uX,uY,angle*bj_RADTODEG)
        call SetUnitAnimation(a.dummy,"birth")
        set a.dX = SPEED*INTERVAL*Cos(angle)
        set a.dY = SPEED*INTERVAL*Sin(angle)
        set a.distance = 0
        set a.terminate = false
        
        return a
    endmethod
    
    static method Hit takes nothing returns boolean
        local unit u = GetFilterUnit()
        local thistype this = thistype.tempData
        if TempUnit == null and CheckTarget(.caster,u) then
            set TempUnit = u
        endif
        set u = null
        return false
    endmethod
    
    
    method Tick takes nothing returns nothing
        local real newX = GetUnitX(.dummy)+.dX
        local real newY = GetUnitY(.dummy)+.dY
        call SetUnitPosition(.dummy,newX,newY)
        set TempUnit = null
        set thistype.tempData = this
        call GroupEnumUnitsInRange(GROUP,newX,newY,IMPACT_SIZE,Filter(function thistype.Hit))
        if TempUnit != null then
            set .terminate = true
            call UnitDamageTarget(.caster,TempUnit,DAMAGE,false,false,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_FIRE,null)
            call DummyCast(.caster,TempUnit,DUMMY_ABILCODE,"creepthunderbolt")
        endif
        set .distance = .distance+SPEED*INTERVAL
    endmethod
    
    method destroy takes nothing returns nothing
        call KillUnit(.dummy)
        set .caster = null
        set .dummy = null
        set .dX = 0
        set .dY = 0
        set .distance = 0
        set .terminate = false
        call .deallocate()
    endmethod
    
endstruct

private function callback takes nothing returns nothing
    local integer i = 1
    local CANNON a
    
    loop
        exitwhen i > I
        set a = DATA[i]
        if a.distance > RANGE or a.terminate == true then
            call a.destroy()
            set DATA[i] = DATA[I]
            set I = I-1
            set i = i-1
        else
            call a.Tick()
        endif
        set i = i+1
    endloop
    
    if I == 0 then
        call PauseTimer(TIMER)
    endif
endfunction

private function Actions takes nothing returns nothing
    local CANNON a = CANNON.create(GetTriggerUnit(),GetSpellTargetX(),GetSpellTargetY())
    
    set I=I+1
    set DATA[I] = a
    
    if I == 1 then
        call TimerStart(TIMER,INTERVAL,true,function callback)
    endif
endfunction

private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == ABILCODE
endfunction    

private function init takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t,Condition(function Conditions))
    call TriggerAddAction(t,function Actions)
    set t = null
endfunction

endscope

If someone's willing, I'll post the entire map and you can have a good look at what might be the cause. If someone can figure out why my code is going to hell, and how I can fix it, I'll name you as a co-creator when I release the map. Not much, I know, but that's all I have to offer.

Thanks in advance!
 
Level 2
Joined
Nov 8, 2012
Messages
7
Normal mode generally works fine, but if you try 'War' mode, you'll see things start getting messed up. The Angel (you'll see what I mean when you play war mode) tends to walk straight past enemies instead of engaging them, one of the angel's primary killing abilities doesn't work on targets yet creates the SFX in the middle of the map, the Demon's Ulti breaks if it gets used multiple times, and the game is likely to crash during periods of intense battle. Also, sometimes the resurrected angel AI players will just hang, but come back to life when attacked. Try playing it a few times to get what I'm really talking about! :p
 
Level 12
Joined
Oct 16, 2010
Messages
680
I added some condition to these if statements

JASS:
if GetPlayerController(Player(i)) == MAP_CONTROL_COMPUTER and i != demonPlayer then
                set angelPlayer = i
            endif

JASS:
set demonPlayer = GetRandomInt(0,11)
        loop
            set i = GetRandomInt(0,11)
            exitwhen i != demonPlayer
        endloop
        set angelPlayer = i

so theres no way that angle and demon can be controlled by the same Player

this is a huge pile of code and i just started testing it, so this is what i found so far

Dark Summoning has a bug. If no Demons 1 is temporarily summoned
if that summoned demon dies or lifetime ends it creates a peasant for the player

imported the UnitDeath actions into an if statement
JASS:
if not IsUnitType(killed,UNIT_TYPE_SUMMONED) then

occasionally AI fails and just standing still
sometimes crushing the game, but it works

Oh and by the way , GetRandomInt() is not really random
player 10 and 12 are repeatedly chosed for controlling angel and demon

well I tried everything ... Still don't have any idea whats wrong with Purge used by AI
if I use it myself, it works great. AI messing it up.
Energize also messing up if given to Angel.

What I don't understand is why do you have Arrays for one angel and one demon?
 
Last edited:
Status
Not open for further replies.
Top