For some reason setNewOwner is called with null when two units die at the same time, possibly even the same frame.
One of the units that dies is lastDefender triggering lastDefenderDeathOrLoad
This presumeably turns the second unit into the lastDefender which is killed by a unit that has the 'Avul' ability at the same time
The result is that the new owner is colored black and hostile to everyone and the enterTrigger is disabled.
I check if the unit is null every time i call setNewOwner(GetOwningPlyer(unit)).
So my only working theory is, that GetOwningPlayer(not null unit) somehow still returns null as a player.
Is this possible?
Here is the full script file as a reference.
Many thanks in advance as i know that this is a lot of stuff to go through
One of the units that dies is lastDefender triggering lastDefenderDeathOrLoad
This presumeably turns the second unit into the lastDefender which is killed by a unit that has the 'Avul' ability at the same time
The result is that the new owner is colored black and hostile to everyone and the enterTrigger is disabled.
I check if the unit is null every time i call setNewOwner(GetOwningPlyer(unit)).
So my only working theory is, that GetOwningPlayer(not null unit) somehow still returns null as a player.
Is this possible?
JASS:
method enter takes unit enteringUnit returns nothing
if(enteringUnit != null or GetUnitAbilityLevel(enteringUnit, 'Avul') == 1 or not GlobalFunctions_UnitAlive(enteringUnit)) then
call setLastDefender(enteringUnit)
call EnableTrigger(leaveTrigger)
call DisableTrigger(enterTrigger)
call setNewOwner(GetOwningPlayer(enteringUnit))
endif
endmethod
method lastDefenderDeathOrLoad takes unit killer returns nothing
local group unitsInOuterRect = null
local boolean isProvinceEmpty
local unit curUnit
if(checkForProvinceEmptyAndSetLastDefender(false)) then
// Check if killer is eligable for conquering a province
if(killer == null or GetUnitAbilityLevel(killer, 'Avul') == 1 or not GlobalFunctions_UnitAlive(killer)) then
set unitsInOuterRect = CreateGroup()
call GroupEnumUnitsInRect(unitsInOuterRect, outerRect, null)
set isProvinceEmpty = true
loop
set curUnit = FirstOfGroup(unitsInOuterRect)
exitwhen curUnit == null
call GroupRemoveUnit(unitsInOuterRect, curUnit)
if(GlobalFunctions_UnitAlive(curUnit) and GetUnitAbilityLevel(curUnit,'Avul') != 1) then
call setLastDefender(curUnit)
call setNewOwner(GetOwningPlayer(curUnit))
set isProvinceEmpty = false
exitwhen true
endif
endloop
// Province is completely empty and the killer cannot conquer the province
if(isProvinceEmpty) then
call setLastDefender(null)
call EnableTrigger(enterTrigger)
call DisableTrigger(leaveTrigger)
call setNewOwner(Player(25))
endif
else
call setLastDefender(killer)
call setNewOwner(GetOwningPlayer(killer))
endif
endif
if(unitsInOuterRect != null) then
call DestroyGroup(unitsInOuterRect)
set unitsInOuterRect = null
endif
set curUnit = null
endmethod
method setNewOwner takes player newOwner returns nothing
local boolean ownerChanged = GetOwningPlayer(barracks) != newOwner
set callbackNewOwner = newOwner
call ForGroup(allBuildings, function setOwner)
if ownerChanged then
call parentRegion.provinceOwnershipChanged()
endif
endmethod
Here is the full script file as a reference.
JASS:
scope Provinces
globals
public Province array startingProvinces
public integer startingProvincesLength = 0
private hashtable provinceReferences = InitHashtable()
private player callbackNewOwner = Player(10)
private player paramFilterGetUnitsInRectOfNonDefenderPlayer = Player(10)
endglobals
private function setOwner takes nothing returns nothing
call SetUnitOwner(GetEnumUnit(), callbackNewOwner, true)
endfunction
private function getProvince takes trigger triggeringTrigger returns Province
return LoadInteger(provinceReferences, GetHandleId(triggeringTrigger),0)
endfunction
private function lastDefenderDeath takes nothing returns nothing
local Province province
set province = getProvince(GetTriggeringTrigger())
call province.lastDefenderDeathOrLoad(GetKillingUnit())
endfunction
private function lastDefenderLoad takes nothing returns nothing
local Province province
set province = getProvince(GetTriggeringTrigger())
call province.lastDefenderDeathOrLoad(null)
endfunction
private function enterRegion takes nothing returns nothing
local Province province
set province = getProvince(GetTriggeringTrigger())
call province.enter(GetTriggerUnit())
endfunction
private function leaveRegion takes nothing returns nothing
local Province province
set province = getProvince(GetTriggeringTrigger())
call province.leave(GetTriggerUnit())
endfunction
private function filterGetUnitsInRectOfNonDefender takes nothing returns boolean
return GetOwningPlayer(GetEnumUnit()) != paramFilterGetUnitsInRectOfNonDefenderPlayer
endfunction
struct Province
private boolean hasStartingUnit = false
private rect innerRect
private rect outerRect
private unit barracks
private unit lastDefender
private group allBuildings
private location circleOfPowerCenter
private trigger enterTrigger
private trigger deathTrigger
private trigger loadTrigger
private trigger leaveTrigger
private Region parentRegion
static method create takes unit circleOfPower, group allBuildings, unit startingUnit returns Province
local Province this = Province.allocate()
local region innerRegion
local integer centerX
local integer centerY
local integer i = 0
set this.circleOfPowerCenter = GetUnitLoc(circleOfPower)
set centerX = R2I(GetLocationX(circleOfPowerCenter))
set centerY = R2I(GetLocationY(circleOfPowerCenter))
set this.innerRect = Rect(centerX - 100, centerY - 100, centerX + 100, centerY + 100)
set this.outerRect = Rect(centerX - 150, centerY - 150, centerX + 150, centerY + 150)
set this.barracks = FirstOfGroup(allBuildings)
set this.allBuildings = allBuildings
set innerRegion = CreateRegion()
call RegionAddRect(innerRegion, innerRect)
set this.enterTrigger = CreateTrigger()
call TriggerRegisterEnterRegion(enterTrigger, innerRegion, null)
call TriggerAddAction( enterTrigger, function enterRegion )
set this.leaveTrigger = CreateTrigger()
call TriggerRegisterLeaveRegion(leaveTrigger, innerRegion, null)
call TriggerAddAction( leaveTrigger, function leaveRegion )
if (startingUnit != null) then
call this.setLastDefender(startingUnit)
call DisableTrigger(enterTrigger)
set this.hasStartingUnit = true
else
set startingProvinces[startingProvincesLength] = this
set startingProvincesLength = startingProvincesLength + 1
call DisableTrigger(leaveTrigger)
endif
call SaveInteger(provinceReferences, GetHandleId(leaveTrigger),0,this)
call SaveInteger(provinceReferences, GetHandleId(enterTrigger),0,this)
set innerRegion = null
return this
endmethod
method init takes player startingPlayer returns nothing
local unit startingUnit
set startingUnit = CreateUnit(startingPlayer, 'e001', GetLocationX(circleOfPowerCenter), GetLocationY(circleOfPowerCenter), 0)
call setLastDefender(startingUnit)
call DisableTrigger(enterTrigger)
call EnableTrigger(leaveTrigger)
call setNewOwner(startingPlayer)
call Power_adjustPlayerPower(startingPlayer, 1)
set startingUnit = null
endmethod
method enter takes unit enteringUnit returns nothing
if(enteringUnit != null or GetUnitAbilityLevel(enteringUnit, 'Avul') == 1 or not GlobalFunctions_UnitAlive(enteringUnit)) then
call setLastDefender(enteringUnit)
call EnableTrigger(leaveTrigger)
call DisableTrigger(enterTrigger)
call setNewOwner(GetOwningPlayer(enteringUnit))
endif
endmethod
method leave takes unit triggeringUnit returns nothing
local group enemiesInRect = null
local unit curUnit = null
local boolean provinceWasForfeit = false
if(triggeringUnit != lastDefender) then
return
endif
if(checkForProvinceEmptyAndSetLastDefender(true)) then
set enemiesInRect = CreateGroup()
set paramFilterGetUnitsInRectOfNonDefenderPlayer = GetOwningPlayer(triggeringUnit)
call GroupEnumUnitsInRect(enemiesInRect, innerRect, function filterGetUnitsInRectOfNonDefender)
if IsUnitGroupEmptyBJ(enemiesInRect) then
call SetUnitPositionLoc(triggeringUnit, circleOfPowerCenter)
else
loop
set curUnit = FirstOfGroup(enemiesInRect)
exitwhen curUnit == null
call GroupRemoveUnit(enemiesInRect, curUnit)
if(GlobalFunctions_UnitAlive(curUnit) and GetUnitAbilityLevel(curUnit,'Avul') != 1) then
call setLastDefender(curUnit)
call setNewOwner(GetOwningPlayer(curUnit))
set provinceWasForfeit = true
exitwhen true
endif
endloop
if not provinceWasForfeit then
call SetUnitPositionLoc(triggeringUnit, circleOfPowerCenter)
endif
endif
endif
if enemiesInRect != null then
call DestroyGroup(enemiesInRect)
set enemiesInRect = null
endif
set curUnit = null
endmethod
method lastDefenderDeathOrLoad takes unit killer returns nothing
local group unitsInOuterRect = null
local boolean isProvinceEmpty
local unit curUnit
if(checkForProvinceEmptyAndSetLastDefender(false)) then
// Check if killer is eligable for conquering a province
if(killer == null or GetUnitAbilityLevel(killer, 'Avul') == 1 or not GlobalFunctions_UnitAlive(killer)) then
set unitsInOuterRect = CreateGroup()
call GroupEnumUnitsInRect(unitsInOuterRect, outerRect, null)
set isProvinceEmpty = true
loop
set curUnit = FirstOfGroup(unitsInOuterRect)
exitwhen curUnit == null
call GroupRemoveUnit(unitsInOuterRect, curUnit)
if(GlobalFunctions_UnitAlive(curUnit) and GetUnitAbilityLevel(curUnit,'Avul') != 1) then
call setLastDefender(curUnit)
call setNewOwner(GetOwningPlayer(curUnit))
set isProvinceEmpty = false
exitwhen true
endif
endloop
// Province is completely empty and the killer cannot conquer the province
if(isProvinceEmpty) then
call setLastDefender(null)
call EnableTrigger(enterTrigger)
call DisableTrigger(leaveTrigger)
call setNewOwner(Player(25))
endif
else
call setLastDefender(killer)
call setNewOwner(GetOwningPlayer(killer))
endif
endif
if(unitsInOuterRect != null) then
call DestroyGroup(unitsInOuterRect)
set unitsInOuterRect = null
endif
set curUnit = null
endmethod
method setLastDefender takes unit newLastDefender returns nothing
set lastDefender = newLastDefender
if(deathTrigger != null) then
call DestroyTrigger(deathTrigger)
endif
if(loadTrigger != null) then
call DestroyTrigger(loadTrigger)
endif
if(lastDefender != null) then
set deathTrigger = CreateTrigger()
call TriggerRegisterUnitEvent(deathTrigger, lastDefender, EVENT_UNIT_DEATH)
call TriggerAddAction( deathTrigger, function lastDefenderDeath )
call SaveInteger(provinceReferences, GetHandleId(deathTrigger), 0, this)
set loadTrigger = CreateTrigger()
call TriggerRegisterUnitEvent( loadTrigger, lastDefender, EVENT_UNIT_LOADED )
call TriggerAddAction( loadTrigger, function lastDefenderLoad )
call SaveInteger(provinceReferences, GetHandleId(loadTrigger), 0, this)
if(not RectContainsUnit(innerRect, lastDefender)) then
call SetUnitPositionLoc(lastDefender, circleOfPowerCenter)
endif
endif
endmethod
method checkForProvinceEmptyAndSetLastDefender takes boolean useInnerRect returns boolean
local group defendingUnits = CreateGroup()
local unit curUnit
local boolean isProvinceEmpty
set bj_groupEnumOwningPlayer = GetOwningPlayer(barracks)
if (useInnerRect) then
call GroupEnumUnitsInRect(defendingUnits, innerRect, filterGetUnitsInRectOfPlayer)
else
call GroupEnumUnitsInRect(defendingUnits, outerRect, filterGetUnitsInRectOfPlayer)
endif
set isProvinceEmpty = true
loop
set curUnit = FirstOfGroup(defendingUnits)
exitwhen curUnit == null
call GroupRemoveUnit(defendingUnits, curUnit)
if(curUnit != lastDefender and GlobalFunctions_UnitAlive(curUnit) and GetUnitAbilityLevel(curUnit,'Avul') != 1) then
call setLastDefender(curUnit)
set isProvinceEmpty = false
exitwhen true
endif
endloop
call DestroyGroup(defendingUnits)
set defendingUnits = null
set curUnit = null
return isProvinceEmpty
endmethod
method setNewOwner takes player newOwner returns nothing
local boolean ownerChanged = GetOwningPlayer(barracks) != newOwner
set callbackNewOwner = newOwner
call ForGroup(allBuildings, function setOwner)
if ownerChanged then
call parentRegion.provinceOwnershipChanged()
endif
endmethod
method isStronghold takes nothing returns boolean
return hasStartingUnit
endmethod
method getOwner takes nothing returns player
return GetOwningPlayer(barracks)
endmethod
method setParentRegion takes Region newParentRegion returns nothing
set parentRegion = newParentRegion
endmethod
endstruct
// no need to destroy groups, they are globally static and therefore no leaks
public function createProvince takes nothing returns nothing
local Province newProvince = Province.create(udg_ParamProvinceCircle, udg_ParamProvinceBuildings, udg_ParamProvinceStartingUnit)
set Regions_paramRegionProvinces[Regions_paramRegionProvincesLength] = newProvince
set Regions_paramRegionProvincesLength = Regions_paramRegionProvincesLength + 1
// reset the global parameter so the next iteration can begin without destroying or clearing something in gui
set udg_ParamProvinceCircle = null
set udg_ParamProvinceBuildings = CreateGroup()
set udg_ParamProvinceStartingUnit = null
endfunction
endscope
Many thanks in advance as i know that this is a lot of stuff to go through












