[SOLVED] Help with slavery mechanic

TheOneHitPupper

Chieftain
Joined
Jun 15, 2017
Messages
98
I'm trying to make a generic notification for the player after an enemy unit is killed and turned into a slave. I have the code necessary for the switch, but don't understand how to tie a notification to it. So far, I can only get it to work when an enemy enslaves the human player's units, which is the opposite of what I want. Here's the script I'm working with:

Code:
print("Battle capture script loaded")

include("MischaIteratingPlotsFunctions")
include("CityNearbyMapDatasV4")

function BattleCapture(iPlayer, iUnit, iUnitType, iX, iY, bDelay, iByPlayer)

    local pPlayer = Players[iPlayer]
    local pByPlayer = Players[iByPlayer]
    local teamID = pPlayer:GetTeam()
    local pPlayerTeam = Teams[teamID]
    local pUnit = pPlayer:GetUnitByID(iUnit)
    print("Unit destroyed")

    print("iPlayer = " .. iPlayer)
    print("iByPlayer = " .. iByPlayer)
    
    -- Must have been killed by another Player
    if iPlayer == iByPlayer then return end
    if iByPlayer == -1 then return end
    
    local pPlot = pUnit:GetPlot()   
    for pAdjacentPlot in PlotAreaSweepIterator(pPlot, 1, SECTOR_NORTH, DIRECTION_CLOCKWISE, DIRECTION_OUTWARDS, CENTRE_EXCLUDE) do
        print("Checking plot")
        for iVal = 0,(pAdjacentPlot:GetNumUnits() - 1) do
            print("Checking unit")
            local loopUnit = pAdjacentPlot:GetUnit(iVal)
            if loopUnit:GetOwner() ~= iPlayer then
                print("Not same owner")
                local loopUnitOwner = loopUnit:GetOwner()
                local otherPlayer = Players[loopUnitOwner]
                local otherTeamID = otherPlayer:GetTeam()
                local loopDMG = loopUnit:GetDamage()
                if pPlayerTeam:IsAtWar(otherTeamID) then
                    if not (pAdjacentPlot:IsCity()) then
                        print("Target affected")
                        local sUnitType = GameInfoTypes.UNIT_LABORER_FREE
                        local nUnit = Players[iByPlayer]:InitUnit(sUnitType, pAdjacentPlot:GetX(), pAdjacentPlot:GetY())
                        nUnit:SetDamage(loopDMG)
                        print("Laborer spawned")
                        
                        if pPlayer:IsHuman() then
                            local title = "Enslaved Laborers!";
                            local descr = "You have successfully captured an enemy unit and enslaved them!";
                            pPlayer:AddNotification(NotificationTypes.NOTIFICATION_GENERIC, descr, title, pAdjacentPlot:GetX(), pAdjacentPlot:GetY());   
                            print("Notification added")
                        end
                    end
                end
            end
        end
    end   
end
GameEvents.UnitPrekill.Add(BattleCapture)

I've tried adding a notification onto pByPlayer because that's the variable that specifies which player's attacking and killing the other unit, but it doesn't execute at all when I do that. I don't see any log errors either. Any suggestions?
 
In this section of your code, you'll want to replace both instances of pPlayer with pByPlayer:
Code:
if pPlayer:IsHuman() then
    local title = "Enslaved Laborers!";
    local descr = "You have successfully captured an enemy unit and enslaved them!";
    pPlayer:AddNotification(NotificationTypes.NOTIFICATION_GENERIC, descr, title, pAdjacentPlot:GetX(), pAdjacentPlot:GetY());   
    print("Notification added")
end

pPlayer is currently defined to point to the player whose unit has just been killed, while pByPlayer points to the player responsible for the killing. Hence, the code as it currently stands provides a notification when your unit gets enslaved by a rival player.

If I'm interpreting your message correctly, I suspect that you initially changed the code such that pByPlayer called AddNotification, but left it so that pPlayer was calling IsHuman. In this case, the reason the message didn't fire is because it was checking for whether it was the human player whose unit was enslaved— and then sending the notification, not to the human, but to the AI player who enslaved the unit.

By changing both cases of pPlayer to pByPlayer, though, the notification should fire as intended.
 
In this section of your code, you'll want to replace both instances of pPlayer with pByPlayer:
Code:
if pPlayer:IsHuman() then
    local title = "Enslaved Laborers!";
    local descr = "You have successfully captured an enemy unit and enslaved them!";
    pPlayer:AddNotification(NotificationTypes.NOTIFICATION_GENERIC, descr, title, pAdjacentPlot:GetX(), pAdjacentPlot:GetY());  
    print("Notification added")
end

pPlayer is currently defined to point to the player whose unit has just been killed, while pByPlayer points to the player responsible for the killing. Hence, the code as it currently stands provides a notification when your unit gets enslaved by a rival player.

If I'm interpreting your message correctly, I suspect that you initially changed the code such that pByPlayer called AddNotification, but left it so that pPlayer was calling IsHuman. In this case, the reason the message didn't fire is because it was checking for whether it was the human player whose unit was enslaved— and then sending the notification, not to the human, but to the AI player who enslaved the unit.

By changing both cases of pPlayer to pByPlayer, though, the notification should fire as intended.
Haha to think it was something that simple. Thank you for the easy to understand explanation. I'm awful writing in Lua. If you could help, I've run into another problem, one that's been perplexing me for hours now.

In-game, the code spawns a Laborer unit successfully, but if the attacking unit has another friendly unit next to them, it will spawn 2 Laborers instead. I've sort of cannibalized the code from another script and to rectify this issue I've been trying to get rid of all the loop variables. The new code I have initiates in-game with no log errors, but doesn't actually spawn any Laborers when it's supposed to. Any ideas? This is the code:

Code:
print("Battle capture script loaded")

include("MischaIteratingPlotsFunctions")
include("CityNearbyMapDatasV4")

function JFD_GetRandom(lower, upper)
    return Game.Rand((upper + 1) - lower, "") + lower
end

function BattleCapture(iPlayer, iUnit, iUnitType, iX, iY, bDelay, iByPlayer)

    local pPlayer = Players[iPlayer]
    local pByPlayer = Players[iByPlayer]
    local teamID = pPlayer:GetTeam()
    local pPlayerTeam = Teams[teamID]
    local pUnit = pPlayer:GetUnitByID(iUnit)
    print("Unit destroyed")

    print("iPlayer = " .. iPlayer)
    print("iByPlayer = " .. iByPlayer)
    
    -- Must have been killed by another Player
    if iPlayer == iByPlayer then return end
    if iByPlayer == -1 then return end
    
    local pPlot = pUnit:GetPlot()   
    print("pUnitOwner is " .. pUnit:GetOwner())
    if pUnit:GetOwner() ~= iByPlayer then
        print("Not same owner")
        local pUnitOwner = pUnit:GetOwner()
        local otherTeamID = pByPlayer:GetTeam()
        local loopDMG = pUnit:GetDamage()
        if pPlayerTeam:IsAtWar(otherTeamID) then
            local randomNumber = JFD_GetRandom(1, 100)
            print("DMG is " .. loopDMG .. ", random number is " .. randomNumber)
            if (randomNumber < 100) and not (pPlot:IsCity()) then
                print("Target affected")
                local sUnitType = GameInfoTypes.UNIT_LABORER_FREE
                local nUnit = pByPlayer:InitUnit(sUnitType, pPlot:GetX(), pPlot:GetY())
                nUnit:SetDamage(loopDMG)
                print("Laborer spawned")
                
                if pByPlayer:IsHuman() then
                    local title = "Enslaved Laborers!";
                    local descr = "You have successfully captured an enemy unit and enslaved them!";
                    pByPlayer:AddNotification(NotificationTypes.NOTIFICATION_GENERIC, descr, title, pPlot:GetX(), pPlot:GetY());   
                    print("Notification added")
                end
            end
        end
    end   
end
GameEvents.UnitPrekill.Add(BattleCapture)
 
Found the problem. The damage applied to the new unit was 100, so the Laborer Unit would instantly die. Another easy fix haha. Here's the code for anyone interested.

Code:
print("Battle capture script loaded")

include("MischaIteratingPlotsFunctions")
include("CityNearbyMapDatasV4")

function JFD_GetRandom(lower, upper)
    return Game.Rand((upper + 1) - lower, "") + lower
end

function BattleCapture(iPlayer, iUnit, iUnitType, iX, iY, bDelay, iByPlayer)

    local pPlayer = Players[iPlayer]
    local pByPlayer = Players[iByPlayer]
    local teamID = pPlayer:GetTeam()
    local pPlayerTeam = Teams[teamID]
    local pUnit = pPlayer:GetUnitByID(iUnit)
    print("Unit destroyed")

    print("iPlayer = " .. iPlayer)
    print("iByPlayer = " .. iByPlayer)
   
    -- Must have been killed by another Player
    if iPlayer == iByPlayer then return end
    if iByPlayer == -1 then return end
   
    local pPlot = pUnit:GetPlot()  
    print("pUnitOwner is " .. pUnit:GetOwner())
    if pUnit:GetOwner() ~= iByPlayer then
        print("Not same owner")
        local pUnitOwner = pUnit:GetOwner()
        local otherTeamID = pByPlayer:GetTeam()
        if pPlayerTeam:IsAtWar(otherTeamID) then
            local randomNumber = JFD_GetRandom(1, 100)
            if (randomNumber < 25) and not (pPlot:IsCity()) then
                print("Target affected")
                local sUnitType = GameInfoTypes.UNIT_LABORER_FREE
                local nUnit = pByPlayer:InitUnit(sUnitType, pPlot:GetX(), pPlot:GetY())
                nUnit:SetDamage(80)
                print("Laborer spawned")
               
                if pByPlayer:IsHuman() then
                    local title = "Enslaved Laborers!";
                    local descr = "You have successfully captured an enemy unit and enslaved them!";
                    pByPlayer:AddNotification(NotificationTypes.NOTIFICATION_GENERIC, descr, title, pPlot:GetX(), pPlot:GetY());  
                    print("Notification added")
                end
            end
        end
    end  
end
GameEvents.UnitPrekill.Add(BattleCapture)
 
Top Bottom