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

[vJASS] Economy System Error (Null variable error?)

Status
Not open for further replies.
Level 6
Joined
Jan 31, 2009
Messages
166
I have been experiencing a persistent and obnoxious bug in one of my map Fortress builders economy system.

The system is supposed to tally up the amount of units with certain abilities that players have that signify those units produce or consume certain resources. The system then decides whether they have a surplus of that resource or if they need more and buy or sells that resource to a global market accordingly. Resources are dynamically priced based on supply and demand. All of this normally works fine.

The problem after a period of time (usually about an hour) in multiplayer games the system starts to fall apart. Specifically the resources start failing to trade one at a time. The economy report (which tells a player all the transactions made each income) starts growing shorter and eventually becomes full of null values. (it just prints out the word null a bunch of times). I think this is caused by one of the methods quitting prematurely due to encountering a null variable. But I do not know which variable is causing this.

If anyone could help me find the null variable by inspecting my code, or knows a good technique for finding null variables (the only one I know is spamming BJDebug messages and trying to see which lines of code are reached) I would be very greatful.

To make matters worst I have not been able to replicate the error in single player. Only in multiplayer and only after a decent period of time.

Here are the methods I suspect might be causing the error
JASS:
   // Update the prices for each comodity as stored in the CommodityPrices array.
        // Prices are then used in both the main economy and to update the multiboard.
        private static method updatePrices takes nothing returns nothing
            local integer PriceCommodityIndex = 1
            local real Price = 1
            
            loop
                set GlobalDemand = 0
                set GlobalSupply = 0
                    
                set LoopIndex = 1
                loop 
                    set LoopPlayer = Player(LoopIndex - 1)

                    set Demand[LoopIndex] = ComputeCommodityProduction(ConsumptionID[PriceCommodityIndex], ConsumptionPerLevel[PriceCommodityIndex], LoopPlayer)
                    set Supply[LoopIndex] = ComputeCommodityProduction(ProductionID[PriceCommodityIndex], ProductionPerLevel[PriceCommodityIndex], LoopPlayer)
                    
                    set GlobalSupply = GlobalSupply + Supply[LoopIndex]
                    set GlobalDemand = GlobalDemand + Demand[LoopIndex]
                    
                    exitwhen LoopIndex > 9
                    set LoopIndex = LoopIndex + 1
                    
                endloop
                
                set GlobalSupply = GlobalSupply + NPCSupply[PriceCommodityIndex]
                set GlobalDemand = GlobalDemand + NPCDemand[PriceCommodityIndex]
                

                set Price = NPCPrice[CommodityIndex] // Price to be used if there is no supply to avoid
                // a division by zero error.
                
                if GlobalSupply > 0 then
                    set Price = CalculateCommodityPrice(BasePrice[PriceCommodityIndex], I2R(GlobalDemand), I2R(GlobalSupply))
                endif
                
                set CommodityPrices[PriceCommodityIndex] = Price
                exitwhen PriceCommodityIndex == CommodityTotal
                set PriceCommodityIndex = PriceCommodityIndex + 1
            endloop
        
        endmethod
        
        // In this function we determine how much supply and demand there is for each commodity.
        // As we go we store the amount each player is producing as string.
        // Allso deals with tax income
        private static method CommoditiesLoop takes nothing returns nothing
            local real Price = 1
            
                        
            call updatePrices()
            set CommodityIndex = 1
            loop // for each commodity
                
                // Get and store each players demand for the commodity we are working with
                // Also handle their tax income
                set LoopIndex = 1
                loop //for each player
                    set LoopPlayer = Player(LoopIndex - 1)

                    set Demand[LoopIndex] = ComputeCommodityProduction(ConsumptionID[CommodityIndex], ConsumptionPerLevel[CommodityIndex], LoopPlayer)
                    set Supply[LoopIndex] = ComputeCommodityProduction(ProductionID[CommodityIndex], ProductionPerLevel[CommodityIndex], LoopPlayer)
                    set TaxIncome[LoopIndex] =  ComputeCommodityProduction('A037', 1000 , LoopPlayer)
                    exitwhen LoopIndex > 9
                    set LoopIndex = LoopIndex + 1
                endloop
            
                set Price = CommodityPrices[CommodityIndex]
                
                // Store the price of the commodity we are working with (printer 1 will be printed to all players)
                set printer[1] = printer[1] + CommodityName[CommodityIndex] + " costs "  + R2S(Price) + " || "
                
                // Print to each player how much they have and require of each commodity.
                // Then print out how much money they made or lost on each commodity.
                set LoopIndex = 1
                loop
                    set LoopPlayer = Player(LoopIndex - 1)
                    set printer2[LoopIndex] = printer2[LoopIndex] + "You have " + I2S (Supply[LoopIndex]) + " " + CommodityName[CommodityIndex] + " || "
                    
                    set printer3[LoopIndex] = printer3[LoopIndex] + "You require " + I2S (Demand[LoopIndex]) + " " + CommodityName[CommodityIndex] + " || "
                    
                    set CurrencyCalculation = R2I((Supply[LoopIndex]-Demand[LoopIndex]) * Price)
                    
                    if (CurrencyCalculation > 0) then
                        set printer4[LoopIndex] = printer4[LoopIndex] + "|c0000cc00 You made " + I2S (CurrencyCalculation) + " Currency selling " + CommodityName[CommodityIndex] + "|r || "
                    elseif (CurrencyCalculation < 0) then
                        set printer4[LoopIndex] = printer4[LoopIndex] + "|c00990000 You lost " + I2S (IAbsBJ(CurrencyCalculation)) + " Currency buying " + CommodityName[CommodityIndex] + "|r||"
                    else
                        set printer4[LoopIndex] = printer4[LoopIndex] + "|c00999999You did not trade " +  CommodityName[CommodityIndex] + "|r || "
                    endif
                    
                    set total[LoopIndex] = total[LoopIndex] +  CurrencyCalculation
                    exitwhen LoopIndex > 9
                    set LoopIndex = LoopIndex + 1
                endloop
                
                // When half the information for half commodities have been stored in the pritners display the information to the screne and clear them
                if CommodityIndex == 3 then
                    call PrintInfo()
                    call InitPrinters()
                endif
                
                // Exit the loop when all commodities have been looped through
                exitwhen CommodityIndex == CommodityTotal
                set CommodityIndex = CommodityIndex + 1
            endloop // Exit commodities loop
            
        endmethod
And here is the entire system

JASS:
// Fix bug where part of the econmy dissapers!


// Needs to be fixed to use proper timer
// Also requires balance (chek spreadsheet) The sprad should more accuratly represnt true prices with new curve.



// Consider adding
// Global Economy Reports
// Sabatoge
// NPC supply/demand/events

// Strech goals
// Banking
// Population system

struct EconomySystem        
        
        // Very Long list of private static variables used in econ system
        
        // These variables represent the stats of each commodity. They should not change over the course of the game.
        private static string array CommodityName // Eg Grain, Gold, Jewlry
        private static integer array ProductionID
        private static integer array ConsumptionID
        private static integer array ProductionPerLevel
        private static integer array ConsumptionPerLevel
        private static integer array NPCPrice // Amount the NPC will charge if no one is supplying it.
        private static integer array NPCSupply
        private static integer array NPCDemand
        private static integer array NPCAverage
        private static integer CommodityTotal = 6 // Total number of commodities (For loop)
        private static real array BasePrice // Base Price of a commdity
        private static real MerchantBonus = 1.20
        private static real BarbarianPenalty = 0.85
        
        // These variables represent the stats of the demon economy. They should not change over time
        private static real Curruption = udg_Curruption * udg_DemonIncomeMultiplier  //  default value .05 about 12 / 100 This is for demons income
        
        
        // System variables that store temporary information
        private static player LoopPlayer = Player(0) // Used to shorten lines and avoding calying player() repetitivly
        private static integer CommodityIndex = 1 // Just a loop index for the main comodities loop
        private static integer TotalCommerce = 0 // Used to store total amount of money made for demon economy (demons get a percentage of all humans income)
        private static integer LoopIndex = 1
        
        // Variables used to sum up the money a player makes.
        private static integer array TaxIncome
        private static integer AdjustedTotal =0
        private static integer CurrencyCalculation =0 // The amount of money a player will gain or lose from a commdity
        private static integer array total
        
        // Variables used to calculate the cost per commodity each time the economy runs. These chance each time.
        private static real array CommodityPrices
        private static integer array Demand // A players demand for a commodity
        private static integer array Supply // A players supply for a commodity
        private static integer GlobalDemand = 0 // All players demand for a commodity
        private static integer GlobalSupply = 0 // All players supply of a commodity
        
       
        
        
         // These variables are used in order to concatinate many strings together
         // into coherent messages which can be displayed to each payer when the economy report runs.
        private static string array printer 
        private static string array printer2
        private static string array printer3
        private static string array printer4 
        
        private static method onInit takes nothing returns nothing
        
            // Primary trigger runs the economy
            local trigger t = CreateTrigger()
            call TriggerRegisterTimerExpireEventBJ( t, udg_IncomeTimer )
            
            //call TriggerAddCondition(t, function thistype.run)
            call TriggerAddAction(t, function thistype.run)
            set t = null
            
            // Secondary trigger, initilizes multiboard
            set t = CreateTrigger()
            call TriggerRegisterTimerEvent(t,2,false)
            call TriggerAddCondition(t, function thistype.CreateEconomyMultiboard)
            set t = null
            
            // Tirtiary trigger, updates multiboard
            set t = CreateTrigger()
            call TriggerRegisterTimerEvent(t,7,true)
            call TriggerAddCondition(t, function thistype.UpdateEconMultiboard)
            set t = null
            
            debug call BJDebugMsg("Init income system")
            
            // Initialize private variables
            set CommodityTotal = 6
            
            set CommodityName[1] = "Grain"
            set ProductionID[1] = 'A038'
            set ConsumptionID[1] = 'A039'
            set ProductionPerLevel[1] = 1000
            set ConsumptionPerLevel[1] = 100
            set BasePrice[1] = 1.5
            set NPCPrice[1] = 3 
            set NPCAverage[1] = 4000
            
            set CommodityName[2] = "Iron Ore"
            set ProductionID[2] = 'A03A' // 
            set ConsumptionID[2] = 'A03B' // 
            set ProductionPerLevel[2] = 10
            set ConsumptionPerLevel[2] = 10
            set BasePrice[2] = 65 
            set NPCPrice[2] = 100
            set NPCAverage[2] = 90
            
            set CommodityName[3] = "Iron Alloy"
            set ProductionID[3] = 'A03C' // 
            set ConsumptionID[3] = 'A03D' // 
            set ProductionPerLevel[3] = 10
            set ConsumptionPerLevel[3] = 10
            set BasePrice[3] = 140 
            set NPCPrice[3] = 200
            set NPCAverage[3] = 45
            
            set CommodityName[4] = "Swords"
            set ProductionID[4] = 'A03E' // 
            set ConsumptionID[4] = 'A03F' // 
            set ProductionPerLevel[4] = 10
            set ConsumptionPerLevel[4] = 1
            set BasePrice[4] = 320 
            set NPCPrice[4] = 250 
            set NPCAverage[4] = 20
            
            
            set CommodityName[5] = "Mana"
            set ProductionID[5] = 'A03G' // 
            set ConsumptionID[5] = 'A03H' // 
            set ProductionPerLevel[5] = 1000
            set ConsumptionPerLevel[5] = 1000
            set BasePrice[5] = 1 
            set NPCPrice[5] = 2 
            set NPCAverage[5] = 6000
            
            set CommodityName[6] = "Craft Goods"
            set ProductionID[6] = 'A03J' // 
            set ConsumptionID[6] = 'A03I' // 
            set ProductionPerLevel[6] = 10
            set ConsumptionPerLevel[6] = 10
            set BasePrice[6] = 80 
            set NPCPrice[6] = 200 
            set NPCAverage[6] = 75
            
            // Creates some base supply and demand at the start of the game.
            call InitNPCValues()
            
            debug call BJDebugMsg("Init income Finished")
            
        endmethod
        
        // This method is left public for debuging reasons (so it can be reseeded using a debug command)
        // This method sets the NPC suply and demand for each commodity.
        // It should be used only once, at map initilization.
        // Each commodity demand is set to a random variation of an average demand. (called NPCAverage)
        public static method InitNPCValues takes nothing returns nothing
            set LoopIndex = 1
            loop
                exitwhen LoopIndex == 7
                set NPCSupply[LoopIndex] = R2I(I2R(NPCAverage[LoopIndex]) * GetRandomReal(0.5,1.5))
                set NPCDemand[LoopIndex] = R2I(I2R(NPCAverage[LoopIndex]) * GetRandomReal(0.5,1.5))
                debug call BJDebugMsg(CommodityName[LoopIndex] + ": Supply ="  + I2S(NPCSupply[LoopIndex]) + " Demand = " + I2S(NPCDemand[LoopIndex]))
                set LoopIndex = LoopIndex + 1
            endloop
        endmethod
        
        //debuging functions
        public static method SetNPCDemand takes integer TargetCommodityIndex, integer NewDemand returns nothing
            set NPCDemand[TargetCommodityIndex]=NewDemand
            debug call BJDebugMsg("Updating " + I2S(TargetCommodityIndex))
            debug call BJDebugMsg(CommodityName[TargetCommodityIndex] + ": Supply ="  + I2S(NPCSupply[TargetCommodityIndex]) + " Demand = " + I2S(NPCDemand[TargetCommodityIndex]))
        endmethod
        
        public static method SetNPCSupply takes integer TargetCommodityIndex, integer NewSupply returns nothing
            set NPCSupply[TargetCommodityIndex]=NewSupply
            debug call BJDebugMsg("Updating " + I2S(TargetCommodityIndex))
            debug call BJDebugMsg(CommodityName[TargetCommodityIndex] + ": Supply ="  + I2S(NPCSupply[TargetCommodityIndex]) + " Demand = " + I2S(NPCDemand[TargetCommodityIndex]))
        endmethod
        
        // Multiboard stuff starts here
        private static multiboard EconomyMultiboard
        
        private static method SetEconBoardItemValue takes integer x, integer y, string value, real width, boolean title returns nothing
            local multiboarditem tempItem = MultiboardGetItem(EconomyMultiboard,x,y)
            
            call MultiboardSetItemValue(tempItem,value)
            call MultiboardSetItemWidth(tempItem,width)
            call MultiboardSetItemStyle(tempItem, true, false)
            if title == true then
                call MultiboardSetItemValueColor(tempItem, 207,175,55,0)
            endif
        
            set tempItem = null
        endmethod
        
        private static method CreateEconomyMultiboard takes nothing returns boolean
            local integer rowIndex = 1
            local integer finalRow = CommodityTotal + 1
            local real defaultRowWidth = 0.06
           
            set EconomyMultiboard = CreateMultiboard()
            
            
            debug call BJDebugMsg("Init Economy Multiboard")
            
            call MultiboardClear(EconomyMultiboard)
            call MultiboardSetColumnCount(EconomyMultiboard, 4)
            call MultiboardSetRowCount(EconomyMultiboard, finalRow)
            call MultiboardSetTitleText(EconomyMultiboard,"Commodity Prices")
            
            
            // Titles
            call SetEconBoardItemValue(0,0, "Commodity", defaultRowWidth,true)
            call SetEconBoardItemValue(0,1, "Price", defaultRowWidth,true)
            call SetEconBoardItemValue(0,2, "Base Price", defaultRowWidth,true)
            call SetEconBoardItemValue(0,3, "Valuation", defaultRowWidth,true)
            
            loop
                exitwhen rowIndex  == finalRow
                call SetEconBoardItemValue(rowIndex,0, CommodityName[rowIndex], defaultRowWidth,true)
                call SetEconBoardItemValue(rowIndex,1, "0", defaultRowWidth,false)
                call SetEconBoardItemValue(rowIndex,2, R2S(BasePrice[rowIndex]), defaultRowWidth,false)
                call SetEconBoardItemValue(rowIndex,3, "0", defaultRowWidth,false)
                set rowIndex = rowIndex +1
            endloop
            
            call MultiboardDisplay(EconomyMultiboard,true)
            
            return false
        endmethod
        
        private static method GetValuation takes real valuationPrice, integer index returns string
            local string Valuation = "Very Cheap"
            
            if (valuationPrice >= BasePrice[index] * 0.5) then
                set Valuation = "Quite Cheap"
            endif
            if (valuationPrice >= BasePrice[index] * 0.75) then
                set Valuation = "Slighly Cheap"
            endif
            if (valuationPrice >= BasePrice[index]*0.95) then
                set Valuation = "Standard"
            endif
            if (valuationPrice >= BasePrice[index]*1.05) then
                set Valuation = "Above Average"
            endif
            if (valuationPrice >= BasePrice[index] * 1.5) then
                set Valuation = "Quite Expensive"
            endif
            if (valuationPrice >= BasePrice[index] * 2) then
                set Valuation = "Very Expensive"
            endif
            
            return Valuation
        endmethod
        
        private static method UpdateEconMultiboard takes nothing returns boolean
            
            local integer rowIndex = 1
            local integer finalRow = CommodityTotal + 1
            
            debug call BJDebugMsg("Updating multiboard")
            
            call updatePrices()
            loop
                exitwhen rowIndex  == finalRow
                call MultiboardSetItemValue(MultiboardGetItem(EconomyMultiboard,rowIndex,1),R2S(CommodityPrices[rowIndex]))
                call MultiboardSetItemValue(MultiboardGetItem(EconomyMultiboard,rowIndex,3),GetValuation(CommodityPrices[rowIndex], rowIndex))
                set rowIndex = rowIndex +1
            endloop
            
            call MultiboardDisplay(EconomyMultiboard,true)
            
            return false
        endmethod
        
        // Multiboard stuff ends here
        
        // Main trigger which runs the entire economy system.
        // Runs once per economy timer
        public static method run takes nothing returns nothing
            debug call BJDebugMsg("Running Economy System")
            set CommodityIndex = 1 // This needs to be rest every time run is called
            
            // Make sure all printers are full of blank lines (printers are varialbes which concentrate strings)
            call InitPrinters()
            
            // Set the total amount of money each player recives to 0
            call InitTotal()
             
            call PrintToHumans("|c00ffcc00----------------= Economic Report =-----------------|r")
            
            // Calculate the global prices and decide how much money each pleyer gets
            call CommoditiesLoop()
            
            // Communicate prices and buy/sell ratios to all the players
            call PrintInfo()
            call PrintToHumans("|c0000cc00You gain 1000 currency from your personal wealth|r")
            
            // This is where we give all of the players their gold, or take it away if they lost money.
            call DistributeMoney()
            
            // Give the demons resources based on curruption values
            call DemonEconomy()
         
            debug call BJDebugMsg("Economy System Finish")
            //return false
        endmethod
        
        // Fill all the printer variables with blank lines
        private static method InitPrinters takes nothing returns nothing
            //debug call BJDebugMsg("Initing Printers")
            set LoopIndex = 1
                loop
                    set printer[LoopIndex] = ""
                    set printer2[LoopIndex] = ""
                    set printer3[LoopIndex] = ""
                    set printer4[LoopIndex] = ""
                    exitwhen LoopIndex > 9
                    set LoopIndex = LoopIndex + 1
                endloop
            //debug call BJDebugMsg("Done Initing Printers")
        endmethod
        
       
        // reset the total amount of gold each player gets to 0
        private static method InitTotal takes nothing returns nothing
            set LoopIndex = 1
                loop
                    set total[LoopIndex] = 0
                    exitwhen LoopIndex > 9
                    set LoopIndex = LoopIndex + 1
                endloop
        endmethod
        
        // Calculate the amount of a certain commodity is being produced  or used by a certain player.
        public static method ComputeCommodityProduction takes integer ID, integer PerLevel, player whichPlayer returns integer
            local group g
            local integer sum = 0
            local unit u
            
            set g = CreateGroup()
            
            call GroupEnumUnitsOfPlayer(g, whichPlayer, null)
            loop
                set u = FirstOfGroup(g)
                exitwhen u == null
                set sum = sum + GetUnitAbilityLevel(u, ID)
                call GroupRemoveUnit(g, u)
            endloop
            
            call DestroyGroup(g)
            set g = null
            set u = null
            return sum * PerLevel
        endmethod
        
        // Calculate what the price of  commodity should be based on supply, demand, its base price, and a 3/4ths root curve.
        public static method CalculateCommodityPrice takes real BasePrice, real Demand, real Supply returns real
            local real Multiplier = Pow(Demand/Supply, 0.75)
            return BasePrice*Multiplier
        endmethod
        
        // Update the prices for each comodity as stored in the CommodityPrices array.
        // Prices are then used in both the main economy and to update the multiboard.
        private static method updatePrices takes nothing returns nothing
            local integer PriceCommodityIndex = 1
            local real Price = 1
            
            loop
                set GlobalDemand = 0
                set GlobalSupply = 0
                    
                set LoopIndex = 1
                loop 
                    set LoopPlayer = Player(LoopIndex - 1)

                    set Demand[LoopIndex] = ComputeCommodityProduction(ConsumptionID[PriceCommodityIndex], ConsumptionPerLevel[PriceCommodityIndex], LoopPlayer)
                    set Supply[LoopIndex] = ComputeCommodityProduction(ProductionID[PriceCommodityIndex], ProductionPerLevel[PriceCommodityIndex], LoopPlayer)
                    
                    set GlobalSupply = GlobalSupply + Supply[LoopIndex]
                    set GlobalDemand = GlobalDemand + Demand[LoopIndex]
                    
                    exitwhen LoopIndex > 9
                    set LoopIndex = LoopIndex + 1
                    
                endloop
                
                set GlobalSupply = GlobalSupply + NPCSupply[PriceCommodityIndex]
                set GlobalDemand = GlobalDemand + NPCDemand[PriceCommodityIndex]
                

                set Price = NPCPrice[CommodityIndex] // Price to be used if there is no supply to avoid
                // a division by zero error.
                
                if GlobalSupply > 0 then
                    set Price = CalculateCommodityPrice(BasePrice[PriceCommodityIndex], I2R(GlobalDemand), I2R(GlobalSupply))
                endif
                
                set CommodityPrices[PriceCommodityIndex] = Price
                exitwhen PriceCommodityIndex == CommodityTotal
                set PriceCommodityIndex = PriceCommodityIndex + 1
            endloop
        
        endmethod
        
        // In this function we determine how much supply and demand there is for each commodity.
        // As we go we store the amount each player is producing as string.
        // Allso deals with tax income
        private static method CommoditiesLoop takes nothing returns nothing
            local real Price = 1
            
                        
            call updatePrices()
            set CommodityIndex = 1
            loop // for each commodity
                
                // Get and store each players demand for the commodity we are working with
                // Also handle their tax income
                set LoopIndex = 1
                loop //for each player
                    set LoopPlayer = Player(LoopIndex - 1)

                    set Demand[LoopIndex] = ComputeCommodityProduction(ConsumptionID[CommodityIndex], ConsumptionPerLevel[CommodityIndex], LoopPlayer)
                    set Supply[LoopIndex] = ComputeCommodityProduction(ProductionID[CommodityIndex], ProductionPerLevel[CommodityIndex], LoopPlayer)
                    set TaxIncome[LoopIndex] =  ComputeCommodityProduction('A037', 1000 , LoopPlayer)
                    exitwhen LoopIndex > 9
                    set LoopIndex = LoopIndex + 1
                endloop
            
                set Price = CommodityPrices[CommodityIndex]
                
                // Store the price of the commodity we are working with (printer 1 will be printed to all players)
                set printer[1] = printer[1] + CommodityName[CommodityIndex] + " costs "  + R2S(Price) + " || "
                
                // Print to each player how much they have and require of each commodity.
                // Then print out how much money they made or lost on each commodity.
                set LoopIndex = 1
                loop
                    set LoopPlayer = Player(LoopIndex - 1)
                    set printer2[LoopIndex] = printer2[LoopIndex] + "You have " + I2S (Supply[LoopIndex]) + " " + CommodityName[CommodityIndex] + " || "
                    
                    set printer3[LoopIndex] = printer3[LoopIndex] + "You require " + I2S (Demand[LoopIndex]) + " " + CommodityName[CommodityIndex] + " || "
                    
                    set CurrencyCalculation = R2I((Supply[LoopIndex]-Demand[LoopIndex]) * Price)
                    
                    if (CurrencyCalculation > 0) then
                        set printer4[LoopIndex] = printer4[LoopIndex] + "|c0000cc00 You made " + I2S (CurrencyCalculation) + " Currency selling " + CommodityName[CommodityIndex] + "|r || "
                    elseif (CurrencyCalculation < 0) then
                        set printer4[LoopIndex] = printer4[LoopIndex] + "|c00990000 You lost " + I2S (IAbsBJ(CurrencyCalculation)) + " Currency buying " + CommodityName[CommodityIndex] + "|r||"
                    else
                        set printer4[LoopIndex] = printer4[LoopIndex] + "|c00999999You did not trade " +  CommodityName[CommodityIndex] + "|r || "
                    endif
                    
                    set total[LoopIndex] = total[LoopIndex] +  CurrencyCalculation
                    exitwhen LoopIndex > 9
                    set LoopIndex = LoopIndex + 1
                endloop
                
                // When half the information for half commodities have been stored in the pritners display the information to the screne and clear them
                if CommodityIndex == 3 then
                    call PrintInfo()
                    call InitPrinters()
                endif
                
                // Exit the loop when all commodities have been looped through
                exitwhen CommodityIndex == CommodityTotal
                set CommodityIndex = CommodityIndex + 1
            endloop // Exit commodities loop
            
        endmethod
        
        // Prints out half the economy system information at once.
        // Should be called twice, once halfway through the comodities loop and once at the end of the comodities loop
        private static method PrintInfo takes nothing returns nothing
            set LoopIndex = 1
            call PrintToHumans (printer[1])
            loop
                call DisplayTimedTextToPlayer(Player(LoopIndex - 1),0,0,30,printer2[LoopIndex])
                call DisplayTimedTextToPlayer(Player(LoopIndex - 1),0,0,30,printer3[LoopIndex])
                call DisplayTimedTextToPlayer(Player(LoopIndex - 1),0,0,30,printer4[LoopIndex])
                exitwhen LoopIndex > 9
                set LoopIndex = LoopIndex + 1
            endloop
        
        endmethod
        
        // Give all the players their money, taking into account bonuses and debts.
        private static method DistributeMoney takes nothing returns nothing
            // Bonuses Tax and Totals
            // Culture 1 = Normal, 2 = Mercantalist, 3 = Barb, 4 = Imperial
            set LoopIndex = 1
            loop
                call DisplayTimedTextToPlayer(Player(LoopIndex - 1),0,0,30, "Tax income = " + I2S(TaxIncome[LoopIndex]))
                set total[LoopIndex] = total[LoopIndex] +  1000
                set total[LoopIndex] = total[LoopIndex] + TaxIncome[LoopIndex]
                // Merchant Bonus
                if (udg_CultureType[LoopIndex] == 2) then
                    if (total[LoopIndex] > 0) then
                        set AdjustedTotal = R2I(I2R(total[LoopIndex]) * MerchantBonus)

                    else
                        set AdjustedTotal = total[LoopIndex]
                    endif
                    call DisplayTimedTextToPlayer(Player(LoopIndex - 1),0,0,30, "Total income = " + I2S(total[LoopIndex]) + " With Merchant Bonus = " + I2S(AdjustedTotal))        
                // Barbrian Penalty
                elseif (udg_CultureType[LoopIndex] == 3) then
                    if total[LoopIndex] > 0 then
                        set AdjustedTotal = R2I(I2R(total[LoopIndex]) * BarbarianPenalty)
                    else
                        set AdjustedTotal = total[LoopIndex]
                    endif
                    call DisplayTimedTextToPlayer(Player(LoopIndex - 1),0,0,30, "Total income = " + I2S(total[LoopIndex]) + " With Barbarian Penalty = " + I2S(AdjustedTotal))
                // Everyone else
                else
                    set AdjustedTotal = total[LoopIndex]
                    call DisplayTimedTextToPlayer(Player(LoopIndex - 1),0,0,30, "Total income = " + I2S(AdjustedTotal))
                endif
                
                if (udg_IncomeRansomDeduct[LoopIndex] > 0) then
                    if (udg_IncomeRansomDeduct[LoopIndex] > AdjustedTotal) then
                        set udg_IncomeRansomDeduct[LoopIndex] = udg_IncomeRansomDeduct[LoopIndex] - AdjustedTotal
                        call SetPlayerState(udg_PlayerOwed[LoopIndex], PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(udg_PlayerOwed[LoopIndex],PLAYER_STATE_RESOURCE_GOLD) + AdjustedTotal) 
                        call DisplayTimedTextToPlayer(udg_PlayerOwed[LoopIndex],0,0,30, "You recieved " + I2S(AdjustedTotal) + " Gold from a ransom")
                        call DisplayTimedTextToPlayer(Player(LoopIndex - 1),0,0,30, "Unfortunatly you give up all of your income to pay ransoms you still owe " + I2S(udg_IncomeRansomDeduct[LoopIndex]) + " Gold")
                        set AdjustedTotal = 0
                    else
                        call SetPlayerState(udg_PlayerOwed[LoopIndex], PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(udg_PlayerOwed[LoopIndex],PLAYER_STATE_RESOURCE_GOLD) + udg_IncomeRansomDeduct[LoopIndex]) 
                        call DisplayTimedTextToPlayer(udg_PlayerOwed[LoopIndex],0,0,30, "You recieved " + I2S(AdjustedTotal) + " Gold from a ransom")
                        call DisplayTimedTextToPlayer(Player(LoopIndex - 1),0,0,30, "Unfortunatly you give up " + I2S(udg_IncomeRansomDeduct[LoopIndex]) + " Gold to a ransom")
                        set AdjustedTotal = AdjustedTotal - udg_IncomeRansomDeduct[LoopIndex]
                        set udg_IncomeRansomDeduct[LoopIndex] = 0
                    endif
                endif
                
                call SetPlayerState(Player(LoopIndex - 1), PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(Player(LoopIndex - 1),PLAYER_STATE_RESOURCE_GOLD) + AdjustedTotal)
                set TotalCommerce = TotalCommerce + AdjustedTotal
                exitwhen LoopIndex > 9
                set LoopIndex = LoopIndex + 1
            endloop
        endmethod
        
        private static method DemonEconomy takes nothing returns nothing
            call DisplayTimedTextToPlayer(Player(10),0,0,30, "|c0000cc00 You recieved " + R2S(Curruption * 100.0) +"% of the human economy which is " + R2S(I2R(TotalCommerce)*Curruption) + " Gold |r" )
            call DisplayTimedTextToPlayer(Player(11),0,0,30, "|c0000cc00 You recieved " + R2S(Curruption * 100.0) +"% of the human economy which is " + R2S(I2R(TotalCommerce)*Curruption) + " Gold |r" )
            call AddGold(Player(10), R2I(I2R(TotalCommerce)*Curruption))
            call AddGold(Player(11), R2I(I2R(TotalCommerce)*Curruption))
        endmethod

endstruct

If you would like any clarification about how any part of the system works feel free to ask (I know that it is far from the cleanest of code).

Thank you for your time.

Update: Changed ConvertedPlayer() to use native. Added more comments and simplified code a little.
 
Last edited:
Level 6
Joined
Jan 31, 2009
Messages
166
Thanks for taking a look

@Alima
Good idea. Updated to use the native (not sure why I wasn't in the first place, probably just didn't think about it.)

@PurgeandFire
The variables which start control printing are these
JASS:
private static string array printer // Controls how lines are displayed
private static string array printer2 // Controls how lines are displayed
private static string array printer3 // Controls how lines are displayed
private static string array printer4 //Controls how lines are displayed
They are used to concatenate strings together before they are printed to the screen ina economy report. It is important to note that all four variables are printed to the screen, then cleared and used again each time the system runs. This is important because as the bug occurs the second use gets disrupted first causing half the economy report to be blank, as the game continues the entire economy report goes blank (And gold stops being transacted as well).


This is the part where I talk about a division by zero error.
An error wold occur if the function CalculateCommodityPrice was ever called with a demand (second parameter) of 0. But as you can see I already check to make sure its not zero.
JASS:
set Price = NPCPrice[CommodityIndex] // Price to be used if there is no supply to avoid // a division by zero error.
                    
if GlobalSupply > 0 then
       set Price = CalculateCommodityPrice(BasePrice[PriceCommodityIndex],      I2R(GlobalDemand), I2R(GlobalSupply))
endif
 
Status
Not open for further replies.
Top