• 🏆 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] [Zerg Campaign] - Hatchery/Larva crash on certain terrain?

Status
Not open for further replies.
Level 10
Joined
May 31, 2019
Messages
139
Hi. I've noticed a reproducible crash in my Zerg Campaign. I've been able to get it to occur consistently in Chapter Four, if the player expands to the center of the map, where Maiev starts.

beta5_z04_elf_center_base.png


After fiddling with it, the source seems to be my modified Blizzard.j, in the function called SC_Larva_Pull

JASS:
// LARVA - PULL FROM REPOSITORY
//===========================================================================
function SC_Larva_Pull takes integer playerId, integer hatcheryId, real x, real y returns nothing
    local boolean hiddenLarvaExists = CountUnitsInGroup(sc_array_larva_playerHiddenGrp[playerId]) > 0
    local player thisPlayer         = Player(playerId)
    local unit thisLarva            = null
    local boolean debugThis         = false
  
    if hiddenLarvaExists then
        set thisLarva = FirstOfGroup(sc_array_larva_playerHiddenGrp[playerId])
        // In the GUI version, there as a check here for if the larva is alive... not sure it's needed?
        call SetUnitPosition(thisLarva, x, y)
        call ShowUnit(thisLarva, true)
        call SetUnitFacingTimed(thisLarva, GetRandomReal(0, 360), 0)
        //call SetUnitAnimation(thisLarva, "stand")
        call SetUnitAnimation(thisLarva, "birth")
        call QueueUnitAnimation(thisLarva, "stand")
        call GroupRemoveUnit(sc_array_larva_playerHiddenGrp[playerId], thisLarva)
        if debugThis then
            call DisplayTextToPlayer(Player(playerId), 0, 0, "Larva pulled from repo")
        endif
    else
        // Existing larva not found, create a new one
        set thisLarva = CreateUnit(Player(playerId), sc_ZERG_LARVA, x, y, GetRandomReal(0, 360))
        if debugThis then
            call DisplayTextToPlayer(Player(playerId), 0, 0, "Larva created since repo was empty")
        endif  
    endif
  
    if sc_array_larva_hatcheryGrp[hatcheryId] == null then
        set sc_array_larva_hatcheryGrp[hatcheryId] = CreateGroup()
    endif
    if sc_array_larva_playerGrp[playerId] == null then
        set sc_array_larva_playerGrp[playerId] = CreateGroup()
    endif
  
    call GroupAddUnit(sc_array_larva_hatcheryGrp[hatcheryId], thisLarva)
    call GroupAddUnit(sc_array_larva_playerGrp[playerId], thisLarva)
    call UnitRemoveAbility(thisLarva, sc_ABIL_RALLY)
    call SetUnitLifePercentBJ(thisLarva, 100)
    call SetUnitUserData(thisLarva, hatcheryId)
  
    // Fail-safe in case for whatever reason the larva belongs to the wrong player
    if GetOwningPlayer(thisLarva) != thisPlayer then
        call SetUnitOwner(thisLarva, thisPlayer, true)
    endif
  
    // Clear leak
    set thisPlayer = null
    set thisLarva = null  
endfunction

This function is only ever called by SC_Larva_Create, which determines where the larva will go relative to its parent hatchery before calling the above function to actually place it.

JASS:
// LARVA - CREATE
//===========================================================================
function SC_Larva_Create takes integer hatcheryId returns nothing
    local integer playerId      = 0
    local integer larvaCount    = CountUnitsInGroup(sc_array_larva_hatcheryGrp[hatcheryId])
    local real hatcheryX        = 0.00
    local real hatcheryY        = 0.00
    local real larvaAngle       = 0.00
    local real larvaX           = 0.00
    local real larvaY           = 0.00
    local boolean debugThis     = false
   
   
    if debugThis then
        //call DisplayTextToPlayer(Player(playerId), 0, 0, "Hatchery #" + I2S(hatcheryId) + " currently has " + I2S(larvaCount) + " larva.")
    endif  
  
    if larvaCount >= sc_INT_HATCHERY_MAX_LARVA then
        return
    endif
  
    set playerId    = GetPlayerId(GetOwningPlayer(bribe_UDexUnits[hatcheryId]))
    set hatcheryX   = GetUnitX(bribe_UDexUnits[hatcheryId])
    set hatcheryY   = GetUnitY(bribe_UDexUnits[hatcheryId])
    set larvaAngle  = GetRandomReal(sc_REAL_LARVA_SPAWN_ANGLE_MIN, sc_REAL_LARVA_SPAWN_ANGLE_MAX)
    set larvaX      = PolarProjectionX(hatcheryX, sc_REAL_LARVA_SPAWN_DISTANCE, larvaAngle)
    set larvaY      = PolarProjectionY(hatcheryY, sc_REAL_LARVA_SPAWN_DISTANCE, larvaAngle)
  
    if debugThis then
        //call DisplayTextToPlayer(Player(playerId), 0, 0, "Hatchery #" + I2S(hatcheryId) + " is pulling a new larva.")
    endif
      
    call SC_Larva_Pull(playerId, hatcheryId, larvaX, larvaY)
  
    if debugThis then
        //call DisplayTextToPlayer(Player(playerId), 0, 0, "Hatchery #" + I2S(hatcheryId) + " currently has " + I2S(larvaCount) + " larva.")
    endif
  
endfunction

Normally, the Hatchery/Larva mechanic works 100% of the time without any issues. I ran a test map that auto-builds >100 hatcheries all over the place just to make sure there was no limit I was hitting somewhere, and no crash or other problem occurred.

I've only been able to experience a crash in Ch.4 of the Zerg Campaign, when expanding to that center gold mine, regardless of how many other hatcheries were on the map. After commenting out various lines of the above functions to narrow it down, I've found that commenting out the lines call SetUnitPosition(thisLarva, x, y) and set thisLarva = CreateUnit(Player(playerId), sc_ZERG_LARVA, x, y, GetRandomReal(0, 360)) from SC_Larva_Pull() prevents the crash, but of course also disables Larvae.

So my guess is there's something the game doesn't like about Larvae being placed at certain positions, but alas I'm totally stumped about what it could be. So I'm just writing this thread in case someone wants to try to tinker with it. It's baffling to me, but probably some peoples' gameplay experience has been negatively impacted by it, so it would be nice to get to the bottom of this if possible.

EDIT: Looks like this is solved, or at least I have not experienced the crash since making the changes in the follow-up post.
 
Last edited:
Level 10
Joined
May 31, 2019
Messages
139
I appear to have solved this issue.

Larvae previously had the "Is Building" flag set to true. The assumption was that this was necessary because they had to "train" dummy units to create the eggs that would hatch into your favorite zergs.

However, after disabling that flag, it seems they are able to continue functioning as normal, and also no longer crash the game!

The World Editor does not support modifying a unit's 'Trains' or 'Upgrade' field if they are not a building, however since this mod's objects are in slk/txt format, we can make such changes without issue.

So when I release the next update (soon) you should be able to safely build Hatcheries wherever, without having to worry about it crashing the game.

1.0_hatcheries_a_okay.png
 
Last edited:
Status
Not open for further replies.
Top