Page 1 of 2 12 LastLast
Results 1 to 50 of 51

Improved Explosion Damage Script, v2.0

  1. #1
    Member Dim@'s Avatar
    Join Date
    Jul 2007
    Location
    Battlecruiser complete

    Improved Explosion Damage Script, v2.0

    While experimenting with capital ships explosion damage, I found that the normal procedure was to create a separate function for every ship you want to implement explosion damage for, which was mostly a duplicate of the other ones, except for a section where you have several DoDamageProximitySobGroup(), that have the various damage radii, and how much is done at each.

    This is quite inefficient (in terms of writing code, if not speed), and also hard to implement, especially if you don't have much experience.

    I have written a function that, I hope, defeats this problem. It works as a single rule, that looks up a table (provided) for the name, and damage radii, of every ship that needs to be checked. It allows you to have a variable number of radii, each with a different amount of damage (to simulate ships further away taking less damage), and a variable number of ships. It takes up a lot less space than older functions, and is very easy to implement. To add a new ship, or change an existing one, you just have to modify or add a few values to the table.

    Updates:
    v1.0 - The original code
    v1.2 - Added better SobGroup splitting, and auto calculation of numbers of ships and radii
    v1.3 - Changed damage from once per death to once per second, added more names to table, lots of general improvements

    v2.0 - Having had a look at the Complex Mod's scripts, I have altered about a third of the code. It is now capable of causing the damage at a specific time, determined by fDeathTime.

    I have also decided, as of version 2.0, to preserve version 1, as the last one, which did damage per second, was very stable and efficient. The code will be left in the spoiler below:

    Explosion Damage, v1.3



    This code up there is only the main part. It doesn't contain SobGroup_SplitGroup, or any documentation. Documentation isn't really needed, as the table is still very similar to the current version, and any important info is in the comments.

    The code for the latest version, however, is below:
    Code:
    ExplosionsTable = 
    {    
        {                                               -- The start of a ship entry in the table
            name = "Hgn_Mothership",                    -- The name of the ship
            numRadii = 0,                               -- How many radii entries there are - leave this, it is set later
            fDeathTime = 6.5,                           -- How long after the ship runs out of health, and starts exploding, should the damage be applied 
            radii =                                     -- The radii table
            {
                {fRange = 1000, fDamage = 10000},       -- An entry, containing the radius (fRange), and amount of damage dealt (fDamage)
                {fRange = 2000, fDamage = 4000 },
            },
        },
        
        {
            name = "Vgr_Mothership",                    -- Another ship entry
            numRadii = 0,
            fDeathTime = 6.5,                           -- Note that this value must be smaller than the ship's sobDieTime, and also,
            radii =                                     -- The difference should be MORE than the sum of fDeathCheckRate and fTimerCheckRate (below)
            {
                {fRange = 1000, fDamage = 8000},
                {fRange = 2000, fDamage = 2000},
                {fRange = 4000, fDamage = 1000},
            },
        },
    }
    
    fDeathCheckRate = 0.1                               -- This affects how often the script checks for dying ships, and starts timing them
    fTimerCheckRate = 0.2                               -- This is how often the script checks if the timers are done, and implement explosion damage
                                                        -- For both of these values, setting them lower will give greater accuracy
                                                        -- In addition, any ship's (sobDieTime - fDeathTime) MUST be greater than the sum of these two
    
    iTotalShips = 0                                         -- Initiating a global variable, to count ships into. Don't set this manually
    
    function initExplDamage()
    
        print("In initExplDamage()")
    
    
        iTotalShips = LengthOf(ExplosionsTable)             -- Count the number of entries in the table
        print(" Counting ships: "..iTotalShips.." in total")-- And therefore the number of ships with Explosion Damage
    
    
        for iShipEntry = 1, iTotalShips do                  -- For each ship, count the number of damage radii
            ExplosionsTable[iShipEntry].numRadii = LengthOf(ExplosionsTable[iShipEntry].radii)
            print(" "..ExplosionsTable[iShipEntry].name.." has "..ExplosionsTable[iShipEntry].numRadii.." damage radii, and an fDeathTime of "..ExplosionsTable[iShipEntry].fDeathTime)
        end
    
        print("Initiating Tabular Explosion Damage, with "..iTotalShips.." ships")
        
        ExplWaitTimers = {}                                 -- Create a table - this will later contain the timers
        for iTempCounter = 1, iTotalShips do
            ExplWaitTimers[iTempCounter] = {}               -- Create sub-tables, one for each ship type
        end                                                 -- Each one will later contain a counter for every ship of that type that is exploding
        
        Rule_AddInterval("LoopThroughExplosionTable", fDeathCheckRate)  -- Add the rule that adds ships to the "Exploding" list, and the timer
        Rule_AddInterval("CheckTimers", fTimerCheckRate)                -- Add the rule that checks the "Exploding" list for ships whose timer has finished
    end
    
    function implementExplDamage(sSobGroup, tDamageTable)      -- This function takes the table that lists damage and radii for that ship
        
        --print ("  A ship/s of type \""..tDamageTable.name.."\" is/are exploding!!")
        for iPlayerIndex = 0, Universe_PlayerCount() - 1 do    -- Go through every player to do damage to
            if (Player_IsAlive(iPlayerIndex) == 1) then        -- If that player is still alive,
                for iDamageEntry = 1, tDamageTable.numRadii do -- Go through every level of damage, as listed in the table
                                                               -- And do damage to all player's ships in proximity
                    SobGroup_DoDamageProximitySobGroup(sSobGroup, iPlayerIndex, tDamageTable.radii[iDamageEntry].fDamage, tDamageTable.radii[iDamageEntry].fRange)
                end
            end
        end
    end
    
    function LoopThroughExplosionTable() 
    
        --print ("In LoopThroughExplosionTable()")
        Update_AllShips()
        SobGroup_Create("TempRuntimeSobGroup")
        SobGroup_Clear("TempRuntimeSobGroup")
        
        for iTableEntry = 1, iTotalShips do                                     -- Go through all the ship entries
        
            local shipName = ExplosionsTable[iTableEntry].name                  -- Inititate the ship's name to the appropriate entry in the table
            local iWaitTimer = FindOrCreateNextEmptySobGroup(shipName)            -- Generate a temporary timer index - this will be used if any ships are dying 
    
            for iPlayerIndex = 0, Universe_PlayerCount() - 1 do                 -- Go through every player
                if (Player_IsAlive(iPlayerIndex) == 1) then                     -- Don't bother for dead players
    
                    Player_FillShipsByType("TempRuntimeSobGroup", iPlayerIndex, shipName) -- Get all ships of that ype
                    local numShips = SobGroup_Count("TempRuntimeSobGroup")                -- Count them
    
                    --if (numShips > 0) then
                        --print (" Player "..iPlayerIndex.." has "..numShips.." ships of type "..shipName)
                    --end
    
                    if (numShips == 1) then                              -- If 1 ship, don't need to split SobGroups
                        CheckShipForDeath("TempRuntimeSobGroup", iWaitTimer, iTableEntry)
    
                    elseif (numShips == 2) then                          -- If 2 ships, SplitGroup won't work, only SplitGroupReference
    
                        local numGroups = SobGroup_SplitGroupReference("sRuntimeGroup2", "TempRuntimeSobGroup", "AllShips", numShips)
                        for iShipIndex = 0, numGroups - 1 do
                            if (SobGroup_Count("sRuntimeGroup2"..iShipIndex) == 1) then
                                CheckShipForDeath("sRuntimeGroup2"..iShipIndex, iWaitTimer, iTableEntry)
                            else
                                print(" [SobGroup Splitting of "..SobGroup_Count("sRuntimeGroup2"..iShipIndex).." of Player "..iPlayerIndex.."'s "..numShips.." "..shipName.."'s failed. Skipping]")
                            end
                        end
                        
                    elseif (numShips > 2) then                           -- Split groups, if not 0 ships (in which case, skip)
    
                        local numGroups = SobGroup_SplitGroup("sRuntimeGroup2", "TempRuntimeSobGroup", numShips)
    
                        for iShipIndex = 0, numGroups - 1 do
                            if (SobGroup_Count("sRuntimeGroup2"..iShipIndex) ~= 1) then    -- If it hasn't split completely, try again with SplitGroupReference
                                print(" [Basic Splitting of "..SobGroup_Count("sRuntimeGroup2"..iShipIndex).." of Player "..iPlayerIndex.."'s "..numShips.." "..shipName.."'s failed. Using SplitGroupReference]")
                                local numGroups2 = SobGroup_SplitGroupReference("sRuntimeGroup3", "sRuntimeGroup2"..iShipIndex, "AllShips", numShips)
                                for iShipIndex2 = 0, numGroups2 - 1 do
                                    if (SobGroup_Count("sRuntimeGroup3"..iShipIndex2) == 1) then
                                        CheckShipForDeath("sRuntimeGroup3"..iShipIndex2, iWaitTimer, iTableEntry)
                                    else
                                        print("  [Advanced Splitting failed. Skipping]")   -- Aaargh! This didn't work either! Oh, well, skip them for now
                                    end
                                end
                            else
                                CheckShipForDeath("sRuntimeGroup2"..iShipIndex, iWaitTimer, iTableEntry) -- It split properly the first time
                            end
                        end
                        
                    end
                end
            end
    
            if (SobGroup_Empty(shipName..iWaitTimer) == 0) then -- This group would have been generated with the temporary timer index and filled with any dying ships
                ExplWaitTimers[iTableEntry][iWaitTimer] = Wait_Start(ExplosionsTable[iTableEntry].fDeathTime) -- If it's empty, it will be used again next time
                print ("Initiating wait timer \"ExplWaitTimers["..iTableEntry.."]["..iWaitTimer.."]\"")
            end                                                 -- If it's not empty, a ship has started exploding, and the actual timer for it is initiated, using the temporary index
        end
    end
    
    function CheckShipForDeath(sSobGroup, iWaitTimer, iShipEntry) -- This is the function that will add dying ships to a the shipName..iWaitTimer group
        if (SobGroup_HealthPercentage(sSobGroup) <= 0) then       -- If the ship is dying, we should add it to the SobGroup, but
            for iSobIndex = 1, iWaitTimer do                      -- We should only add the ship if it hasn't been added before
                if (SobGroup_GroupInGroup(ExplosionsTable[iShipEntry].name..iSobIndex, sSobGroup) == 1) then 
                    return                                        -- Otherwise, we will be wasting memory, AND, it will override other ships that start dying later
                end                                               -- As the function runs several times a second, and the ship has <= 0 health each time
            end
                SobGroup_SobGroupAdd(ExplosionsTable[iShipEntry].name..iWaitTimer, sSobGroup) -- If the function has't returned yet, the ship is a new one - add it
                --print("A ship, "..ExplosionsTable[iShipEntry].name..", ("..sSobGroup..") is dying - adding to SobGroup "..ExplosionsTable[iShipEntry].name..iWaitTimer)
        end
    end
    
    function LengthOf(tTable)
        local iTableLength = 0
    
        repeat
            iTableLength = iTableLength + 1
        until (not tTable[iTableLength + 1])    -- Loop through all. When the next one is nil (false), you have the exact number of entries
    
        return iTableLength
    end
    
    function FindOrCreateNextEmptySobGroup(sSobGroupBaseName) -- This function goes through all the dying ships SobGroups, and finds the first empty one (or creates a new one)
        local bFunctionOver = 0                               -- When this is true, we are done
        local iWaitTimer = 1                                  -- The iterator - the name is standard throughout my script
        while (bFunctionOver == 0) do
            SobGroup_Create(sSobGroupBaseName..iWaitTimer)    -- This will create, if not existing already
            if ( SobGroup_Empty(sSobGroupBaseName..iWaitTimer) == 1 ) then
                bFunctionOver = 1                             -- If it's empty, return the current iWaitTimer
            else
                iWaitTimer = iWaitTimer + 1                   -- Othewise, try again with the next one
            end
        end
        return iWaitTimer                                     -- This value will be used to reference the new SobGroup, and a potentially new Timer variable
    end
    
    function CheckTimers()                                    -- This function goes through all the existing timer variables (in the ExplWaitTimers table)
        for iShipEntry = 1, iTotalShips do                    -- And the associated dying ships SobGroups - if the timer is done, cause damage
            local iWaitTimer = 0
            while (ExplWaitTimers[iShipEntry][iWaitTimer + 1]) do -- Go through all timers, until the next one is nil (i.e. you're on the last one)
                iWaitTimer = iWaitTimer + 1
                if ( SobGroup_Empty(ExplosionsTable[iShipEntry].name..iWaitTimer) == 0 ) then -- If this isn't an empty explosion group,
                    if ( Wait_End(ExplWaitTimers[iShipEntry][iWaitTimer]) == 1 ) then         -- If the time has passed
                        --print ("Implementing damage for ship "..ExplosionsTable[iShipEntry].name.." ("..ExplosionsTable[iShipEntry].name..iWaitTimer.."), with Timer \"ExplWaitTimers["..iShipEntry.."]["..iWaitTimer.."]\"")
                        implementExplDamage(ExplosionsTable[iShipEntry].name..iWaitTimer, ExplosionsTable[iShipEntry])
                        SobGroup_Clear(ExplosionsTable[iShipEntry].name..iWaitTimer)          -- Cause proximity damage, and clear the dying ships group
                        ExplWaitTimers[iShipEntry][iWaitTimer] = 0
                    end
                end
            end
        end
    end
    The above already has a table that does some damage for the vaygr and hiigaran motherships. Note that it is only an example, and should be replaced with your preferred values.

    To implement, paste the above code into deathmatch.lua, also paste the SobGroup_SplitGroup() and SobGroup_SplitGroupReference() functions:

    SplitGroup and SplitGroupReference


    Next, paste the Update_AllShips() function:

    Update_AllShips()


    Finally, and add one line to OnInit(), a function in deathmatch.lua:
    Code:
    initExplDamage()
    voila!

    If you know what you are doing, you may want to paste the scripts into a different file, then add it to your main file using dofilepath().
    Also, if you are already using Update_AllShips(), or the splitting functions (you need both SplitGroup and SplitGroupReference), then you, of course, don't need to copy them again.

    As for the table, here is how it works:

    Whenever you add something, you should make sure it matches the layout of all the others, such as commas, variable names and braces.

    The table is split into sections, each one is a table dedicated to one ship. In that table, the first variable, name, is a string containing the ship's name. The second variable, numRadii, you don't need to set, as the script will automatically count them and set it for its own use.

    Next, the third variable, fDeathTime, is how long after the ship's health runs out the damage is done. This should be set so it matches the time of the big, blinding explosion, as that is the time that it seems logical for nearby ships to get hurt. This should be tailored for individual ships. For example, the Vaygr and Hiigaran motherships both take 7 seconds to die, and the FX explosion occurs about half a second before. So the values are set to 6.5. Note that the time is not exact. Instead, it will be within a range, equal to the sum of fDeathCheckRate and fTimerCheckRate. This isn't too bad, as the blinding flash tends to last for a while, and, at the default range, 0.3 (0.1 + 0.2), the damage should be during this explosion anyway. You can reduce those two values for greater accuracy. Finally, fDeathTime must not only be less than how long the ship takes to die, but the difference must be greater than the sum of the two variables. If it is not, ships will not do damage consistently. To find out how long a ship takes to die, look at the sobDieTime, in the *.ship file.

    After fDeathTime is a table, radii, that contains individual entries. This contains a list of all the radii of damage that a ship will cause upon exploding. You can have any number of radii, so that ships further away don't get damaged as much. Note that they stack, so the closest ships will take damage from every radius, not just the nearest one. fRange is the size of each radius, and fDamage is the damage it causes. They can both be decimals.

    As an example, if you have a ship that has a sobDieTime of 5 seconds, and you want all ships in 500 metres to take 1500 Damage, and 1 km to take 500 damage, one second before death, you will need to create two radii. The inner one should have an fRange of 500, and an fDamage of 1000. This will give all inner ships 1000 damage. The outer radius should have an fRange of 1000, and an fDamage of 500. This will give inner ships an additional 500 damage (for a total of 1500), and outer ships 500. fDeathTime should be set to 4.
    If the ship were named Hgn_NewShip, the table entry would look like this:
    Code:
    {
    name = "Hgn_NewShip",
    numRadii = 0,
    fDeathTime = 4,
    radii =
        {
            {fRange = 500, fDamage = 1000},
            {fRange = 1000, fDamage = 500},
        },
    },
    Finally, after the ExplosionsTable, there are two variables: fDeathCheckRate, and fTimerCheckRate. These control how often the script checks for newly dying ships, and ships due for explosion damage (after fDeathTime has passed), respectively. The time of the explosion damage will only be accurate to the sum of these two. The default values (0.1 and 0.2) add up to 0.3, i.e. three tenths of a second. This is good enough for most ships. If you find you need greater accuracy, you can reduce these values.

    Note once a ship's sobDieTime is over, it disappears completely from the game, and it is no longer possible to apply damage. If the difference between the explosion time and the death time is less than the range, your ships will not explode consistently, as every time the range falls above the sobDieTime, there will be no ship to do explosion damage from.
    Last edited by Dim@; 21st Dec 09 at 3:20 AM. Reason: Updating to version 2.0
    Destroying things is easy.
    Creating things is hard.
    Creating things in order to watch them explode is just plain fun.

    Explosion Damage Script, Scripting Tutorial

  2. #2
    Member Dim@'s Avatar
    Join Date
    Jul 2007
    Location
    Battlecruiser complete
    Edited, to add the SobGroup_SplitGroup() function.

    Also, I have to ask, how do you find how many entries there are in a table?

    There is supposed to be a unary '#' operator to do this, according to the LUA manual, but it's not working.
    It gives me an error.
    I would like to use it, so you don't have to specify the number of ships, and the number of radii for each ship.

  3. #3
    Member ajlsunrise's Avatar
    Join Date
    Jun 2008
    Location
    Binaryland
    you can try using "getn()", but i've found that sometimes that doesn't work...
    so i wrote my own, let me see if i can dig it out of the dust...

    -- EDIT:

    looking closer at your code, you could do this:

    Code:
    ExplosionsTable = 
    {
        iNumShips = 0,
    	fLoopTime = 6, --The total number of ship entries in the table, and how often the function should check for deaths
        
    	Ships = {
    		{   name = "Hgn_Mothership",                          -- A ship entry in the table
    			numRadii = 0,  -- Number of damage radii; leave it at 0, it gets set later.
    			radiiEntries = {
    				{fRange = 4000, fDamage = 9000},    -- An entry, containing the radius, and amount of damage dealt
                    {fRange = 8000, fDamage = 1000},    -- Another such entry
                },
    		},
    		{   name = "Vgr_Mothership",                -- Another ship entry in the table
    			numRadii = 0,
    			radiiEntries = {
    				{fRange = 4000, fDamage = 9800},
                    {fRange = 10000, fDamage = 200},
                },
    		},
        },
    }
    
    function initExplDamage()
    
        local nShips = 0;
    	local bFirstTime = 0;
    	local bEntryFirstTime = 0;
    	local iRadiiEntries = 0;
    	for i, eShip in ExplosionsTable.Ships do
    		nShips = nShips + 1;
    		for j, eRadii in eShip.radiiEntries do
    			iRadiiEntries = iRadiiEntries + 1;
    		end
    		eShip.numRadii = iRadiiEntries;
    	end
    	ExplosionsTable.iNumShips = iShips;
    
        print("Initiating Tabular Explosion Damage, with iNumShips: "..ExplosionsTable[1].iNumShips..", fLoopTime: "..ExplosionsTable[1].fLoopTime.."\n")
        Rule_AddInterval("LoopThroughExplosionTable", ExplosionsTable[1].fLoopTime)
    end

    i don't have time right now to go through the rest of the code and suggest changes, but this will ( or should ) help you A LOT!

    -- EDIT2:
    I made time:
    Code:
    ExplosionsTable = 
    {
        iNumShips = 0, -- this gets set later, so leave it at 0.
        fLoopTime = 6, --The total number of ship entries in the table, and how often the function should check for deaths
        
        Ships = {
            {   name = "Hgn_Mothership",                          -- A ship entry in the table
                numRadii = 0,  -- Number of damage radii; leave it at 0, it gets set later.
                radiiEntries = {
                    {fRange = 4000, fDamage = 9000},    -- An entry, containing the radius, and amount of damage dealt
                    {fRange = 8000, fDamage = 1000},    -- Another such entry
                },
            },
            {   name = "Vgr_Mothership",                -- Another ship entry in the table
                numRadii = 0,
                radiiEntries = {
                    {fRange = 4000, fDamage = 9800},
                    {fRange = 10000, fDamage = 200},
                },
            },
        },
    }
    
    function initExplDamage()
    
        local nShips = 0;
        local bFirstTime = 0;
        local bEntryFirstTime = 0;
        local iRadiiEntries = 0;
        for i, eShip in ExplosionsTable.Ships do
            nShips = nShips + 1;
            for j, eRadii in eShip.radiiEntries do
                iRadiiEntries = iRadiiEntries + 1;
            end
            eShip.numRadii = iRadiiEntries;
        end
        ExplosionsTable.iNumShips = iShips;
    
        print("Initiating Tabular Explosion Damage, with iNumShips: "..ExplosionsTable[1].iNumShips..", fLoopTime: "..ExplosionsTable[1].fLoopTime.."\n")
        Rule_AddInterval("LoopThroughExplosionTable", ExplosionsTable[1].fLoopTime)
    end
    
    function implementExplDamage(sSobGroup, tDamageTable, nRadii)        -- This function takes the table that lists damage and radii for that ship
        
        if (SobGroup_HealthPercentage(sSobGroup) <= 0) then      -- If the ship's dying, do some damage
            print ("  A ship is exploding!!\n")
            for iPlayerIndex = 0, Universe_PlayerCount() - 1 do  -- Go through every player to do damage to
                if (Player_IsAlive(iPlayerIndex) == 1) then      -- If that player is still alive,
                
                    for iDamageEntry = 1, nRadii do -- Go through every level of damage, as listed in the table
                                                                 -- And do damage to all player's ships in proximity
                        SobGroup_DoDamageProximitySobGroup(sSobGroup, iPlayerIndex, tDamageTable[iDamageEntry].fDamage, tDamageTable[iDamageEntry].fRange)
                        print ("   Doing "..tDamageTable[iDamageEntry].fDamage.." damage to all player "..iPlayerIndex.." ships, at range "..tDamageTable[iDamageEntry].fRange.."\n")
                    end
                end
            end
        end
    end
    
    
    
    function LoopThroughExplosionTable() 
    
        print ("In LoopThroughExplosionTable()\n")
    
        for iPlayerIndex = 0, Universe_PlayerCount() - 1 do              -- Go through every player
        
            if (Player_IsAlive(iPlayerIndex) == 1) then                  -- Don't bother for dead players
            
                for iTableEntry = 1, ExplosionsTable.iNumShips do -- Go through all the table entries
        
                    local shipName = ExplosionsTable.Ships[iTableEntry].name     -- Inititate the ship's name to the appropriate entry in the table
    
                    sRuntimeTempSobGroup = Player_GetShipsByType(iPlayerIndex, shipName) -- Get all ships of that ype
                    local numShips = SobGroup_Count(sRuntimeTempSobGroup)                -- Count them
                    
                    print (" Player "..iPlayerIndex.." has "..numShips.." ships of type "..shipName.."\n")
           
                    -- If only a single ship then don't need to go through the headache of splitting SobGroups
                    if (numShips == 1) then
                        implementExplDamage(sRuntimeTempSobGroup, ExplosionsTable.Ships[iTableEntry].radiiEntries, ExplosionsTable.Ships[iTableEntry].numRadii)
                        
                    elseif (numShips ~= 0) then -- Split groups, if not 0 ships (in which case, skip)
    
                        local numGroups = SobGroup_SplitGroup("sRuntimeGroup2", sRuntimeTempSobGroup, numShips)
            
                        for iShipIndex = 0, numGroups - 1 do
    						implementExplDamage("sRuntimeGroup2"..iShipIndex, ExplosionsTable.Ships[iTableEntry].radiiEntries, ExplosionsTable.Ships[iTableEntry].numRadii)
                        end
                    end
                end
            end
        end
    end
    Last edited by ajlsunrise; 18th Dec 09 at 12:34 AM.

  4. #4
    Member Dim@'s Avatar
    Join Date
    Jul 2007
    Location
    Battlecruiser complete
    Updated the script to version 1.2

    It will now split SobGroups properly (the old version would have problems with exactly 2 of a ship), and gives you the chance to not worry about the ship and damage radii numbers.

    Also added basic instructions for using the table.

    Now, please, try out the code, offer suggestions, criticism, and, by all means, ask for help.

    EDIT: And, of course, thanks to ajlsunrise for his ideas on counting the variables in a table (I haven't used your code exactly, though)

  5. #5
    Member mickey's Avatar
    Join Date
    Mar 2008
    Location
    Moscow
    Now I think work in progress!

  6. #6
    Member ajlsunrise's Avatar
    Join Date
    Jun 2008
    Location
    Binaryland
    EDIT: And, of course, thanks to ajlsunrise for his ideas on counting the variables in a table (I haven't used your code exactly, though)
    That's okay, as long as it works for you. Personally I like using "obj.variable" references more than "obj[5]". It doesn't leave as much room for error.

  7. #7
    Member Dim@'s Avatar
    Join Date
    Jul 2007
    Location
    Battlecruiser complete
    Me too, but, unfortunately, because you can have a variable number of ships and radii, I will have to use some of them anyway.

    And, I don't know whether this has something to do with how LUA works, but when I gave the variables names, if there was another variable, such as the radii table, without a name, it gave me an error.

    Notice that I still used names in all the situations where there weren't any unnamed tables alongside them.

    EDIT: Oh, no, no ,no...

    I just realised ... If you set the fLoopTime to the smallest sobDieTime, ships with a longer die time will do more than one wave of damage, as the script has enough time to run twice...

    This will require some rethinking. Any ideas?
    Last edited by Dim@; 18th Dec 09 at 5:20 PM.

  8. #8
    Member ajlsunrise's Avatar
    Join Date
    Jun 2008
    Location
    Binaryland
    Me too, but, unfortunately, because you can have a variable number of ships and radii, I will have to use some of them anyway.
    well of course.

    And, I don't know whether this has something to do with how LUA works, but when I gave the variables names, if there was another variable, such as the radii table, without a name, it gave me an error.
    that shouldn't happen... the radii entries is just a standard table, so is the ships entries...

    Notice that I still used names in all the situations where there weren't any unnamed tables alongside them.
    ummm... i think i notice...

    EDIT: Oh, no, no ,no...

    I just realised ... If you set the fLoopTime to the smallest sobDieTime, ships with a longer die time will do more than one wave of damage, as the script has enough time to run twice...

    This will require some rethinking. Any ideas?
    what are the smallest and largest sobDieTimes?

  9. #9
    Member Dim@'s Avatar
    Join Date
    Jul 2007
    Location
    Battlecruiser complete
    what are the smallest and largest sobDieTimes?
    I am afraid that's not much use - the point is that people can use this in their mod, and their custom ships can have variable sobDieTimes.

    I had an idea to solving this problem - perhaps, instead of running the script once every 7 secs (or so) so it only happens once per sobDieTime, run the script once per second, and put the values for the damage radii as (desiredValue / sobDieTime). That way, instead of doing damage in one big burst, which can be at any time during the explosion, or twice, if the sobDieTime is too long, it will do gradual damage throughout the whole explosion sequence.

    Alternatively, you can do a much more complex solution, where you save a SobGroup that is dying, as well as its location, and, when the SobGroup is empty (i.e. death finished), deal proximity damage to all ships around the location.

  10. #10
    You could also use that for ship that instill of exploding in 1 uber blast, explode after few less damaging blast.

    Even maybe it could be possible to set a random selection of one of those 2 alternative when a ship is being destroyed.

  11. #11
    Member Dim@'s Avatar
    Join Date
    Jul 2007
    Location
    Battlecruiser complete
    Updated to version 1.3

    The script will now run once per second, and the explosion damage will be inflicted every second, instead of once. This will make it a lot more stable and look better in-game.

    I have also used a few more variable names in the table, and it really does look better. So does the code, as "tDamageTable[1]" is replaced with "tDamageTable.name". Also, the tidying up means all loops now start at index 1, instead of 2 or 3.

    Read the instructions, now expanded, for how to use the table properly.

    And, once again, please, try out the code, offer suggestions, criticism, and, by all means, ask for help.

    (I actually copied from my older post for that last part)

  12. #12
    Member ajlsunrise's Avatar
    Join Date
    Jun 2008
    Location
    Binaryland
    you could change this:
    Code:
    if (numShips == 0) then                                  -- Do nothing
    elseif (numShips == 1) then                              -- If 1 ship, don't need to split SobGroups
        ...
    elseif (numShips == 2) then                              -- If 2 ships, SplitGroup won't work, only SplitGroupReference
        ...
    elseif (numShips ~= 0) then
        ...
    end
    into this:
    Code:
    if (numShips == 1) then                              -- If 1 ship, don't need to split SobGroups
        ...
    elseif (numShips == 2) then                              -- If 2 ships, SplitGroup won't work, only SplitGroupReference
        ...
    elseif (numShips > 2) then
        ...
    end
    -- edit: when this is finalized, it needs to be stickied or archived, or done something important with (I was going to say put it on the wiki... but we can't do that...)
    Last edited by ajlsunrise; 18th Dec 09 at 10:44 PM.

  13. #13
    Member Dim@'s Avatar
    Join Date
    Jul 2007
    Location
    Battlecruiser complete
    Wow, thanks for that recommendation.



    As for the if - elseif ladder, I had something similar to that before, but I put the 0 first to save having to perform more checks (given that most players are likely to NOT have most of the ships at any time). Though I guess it isn't really a significant performance increase..

    I may revert if there are any more reasons to update (It works for now, though).

  14. #14
    Member mickey's Avatar
    Join Date
    Mar 2008
    Location
    Moscow
    Thanks Dim@ for this small magic!! It already work!!!
    It is necessary to bring it to perfection!

    I am not assured about slow fall of health of the ships around!
    When the vessel perishes that at first there are small explosions on all hull!
    At these moments the nearest ships hardly should lose health!
    In an ideal it is necessary for us to connect "fLoopTime" with the one main FX-explosion of each vessel!

    Probably to create "fLoopTime" for each vessel separately?
    Last edited by mickey; 19th Dec 09 at 7:29 AM.

  15. #15
    Member Dim@'s Avatar
    Join Date
    Jul 2007
    Location
    Battlecruiser complete
    Ah, but here is the snag.

    fLoopTime is how often the function checks for ship deaths, not how long it takes after a ship starts dying. The best we can do is set the fLoopTime to the individual sobDieTimes of each ship. This was what was done before, and there had to be a different function to look after the explosion of each ship. This meant a lot of code, with most of it duplicated, but still didn't solve the problem, as it basically meant the ship would only cause damage ONCE (rather than slowly, over time), but that once could still be at any time during the explosion.

    I might have another look at the complex scripts, to see if they have anything interesting, but, for now, this is the best we have.

  16. #16
    Hey Dim, I haven't a clue as to where in the deathmatch.lua these codes are supposed to go.

    Can you post where exactly each of these sections of codes are to be inserted into the DM ?

    Also I don't have any file thats called OnInit():
    Last edited by adamstrange; 19th Dec 09 at 6:15 PM.
    strange...as wonderfull as it may be,i'm still...up here... floating...and no one even seems to notice.

  17. #17
    Member Dim@'s Avatar
    Join Date
    Jul 2007
    Location
    Battlecruiser complete
    Here's how it works:

    You must insert these codes ANYWHERE into deathmatch.lua, as long as they're not inside a function or table (i.e. not between two braces, {}, or a "function" and "end" statement). The deathmatch.lua should already be indented, wherever you got it form, so these areas, functions and tables, should be obvious.

    Alternatively, you can create a new file, called something like "ExplDamage.lua", put it in a different folder (you can create a new one, like "lib"), and paste the codes in there. Then add this line anywhere in deathamtch.lua:
    Code:
    dofilepath("data:leveldata\\multiplayer\\lib\\ExplDamage.lua")
    OnInit() isn't a file, it's a function.

    Find this part of deathmatch.lua:
    Code:
    function OnInit()
        MPRestrict()
        Rule_Add("MainRule")
    end
    This is the OnInit function. It is the first thing to be executed when a game loads. Insert "initExplDamage()" anywhere in the function, like this:

    Code:
    function OnInit()
        MPRestrict()
        Rule_Add("MainRule")
    
        initExplDamage()
    end

  18. #18
    Ok I pasted the code into my custom GR and the game won't even start.

    The Italics is my custom code & the bold is your code.
    Code:
    GUID = 
        { 110, 91, 157, 190, 18, 23, 250, 78, 144, 20, 41, 246, 181, 128, 214, 12, }
    GameRulesName = "NR-Warfare"
    Description = "Use this with NR-Warfare Maps which have no Resource Asteroids"
    GameSetupOptions = 
        { 
        { 
            name = "resources", 
            locName = "$3240", 
            tooltip = "$3239", 
            default = 1, 
            visible = 1, 
            choices = 
                { "$3241", "0.5", "$3242", "1.0", "$3243", "2.0", }, }, 
        { 
            name = "unitcaps", 
            locName = "$3214", 
            tooltip = "$3234", 
            default = 1, 
            visible = 1, 
            choices = 
                { "SmallStrike", "SmallStrike", "CarrierStrike", "CarrierStrike", "FrigateWarfare", "FrigateWarfare", "DestroyerOps", 
    
    "DestroyerOps", "Fleet", "Fleet", "FleetWide", "FleetWide", "FullScaleCombat", "FullScaleCombat", }, }, 
        { 
            name = "resstart", 
            locName = "$3205", 
            tooltip = "$3232", 
            default = 0, 
            visible = 1, 
            choices = 
                { "150000", "150000", "350000", "350000", "550000", "550000", "$3209", "0", }, }, 
        { 
            name = "lockteams", 
            locName = "$3220", 
            tooltip = "$3235", 
            default = 0, 
            visible = 1, 
            choices = 
                { "$3221", "yes", "$3222", "no", }, }, 
        { 
            name = "startlocation", 
            locName = "$3225", 
            tooltip = "$3237", 
            default = 0, 
            visible = 1, 
            choices = 
                { "$3226", "random", "$3227", "fixed", }, }, 
        }
    dofilepath("data:scripts/scar/restrict.lua")
    Events = {}
    Events.endGame = 
        { 
            { 
                { "wID = Wait_Start(5)", "Wait_End(wID)", }, 
            }, 
        }
    function OnInit()
        MPRestrict()
        Rule_Add("MainRule")
    
        initExplDamage()
    end
    
    function MainRule()
        local playerIndex = 0
        local playerCount = Universe_PlayerCount()
        while  playerIndex<playerCount do
            if  Player_IsAlive(playerIndex)==1 then
                if  Player_HasShipWithBuildQueue(playerIndex)==0 then
                    Player_Kill(playerIndex)
                end 
    
            end 
    
            playerIndex = (playerIndex + 1)
        end 
    
        local numAlive = 0
        local numEnemies = 0
        local gameOver = 1
        playerIndex = 0
        while  playerIndex<playerCount do
            if  Player_IsAlive(playerIndex)==1 then
                local otherPlayerIndex = 0
                while  otherPlayerIndex<playerCount do
                    if  AreAllied(playerIndex, otherPlayerIndex)==0 then
                        if  Player_IsAlive(otherPlayerIndex)==1 then
                            gameOver = 0
                        else
                            numEnemies = (numEnemies + 1)
                        end 
    
                    end 
    
                    otherPlayerIndex = (otherPlayerIndex + 1)
                end 
    
                numAlive = (numAlive + 1)
            end 
    
            playerIndex = (playerIndex + 1)
        end 
    
        if  numEnemies==0 and numAlive>0 then
            gameOver = 0
        end 
    
        if  gameOver==1 then
            Rule_Add("waitForEnd")
            Event_Start("endGame")
            Rule_Remove("MainRule")
        end 
    
    end
    
    function waitForEnd()
        if  Event_IsDone("endGame") then
            setGameOver()
            Rule_Remove("waitForEnd")
        end 
    
    end
    
    
    
    
    ExplosionsTable = 
    {    
        {                                               -- The start of a ship entry in the table
            name = "Hgn_Mothership",                    -- The name of the ship
            numRadii = 0,                               -- How many radii entries there are - leave this, it is set later
            radii =                                     -- The radii table
            {
                {fRange = 1000, fDamage = 1500},        -- An entry, containing the radius, and amount of damage dealt
                {fRange = 2000, fDamage = 400},         -- Set the fDamage, which can be a decimal, to your ( desired damage / the ship's 
    
    sobDieTime ),
            },                                          --  as the damage is dealt every second, not once during the explosion
        },
        
        {
            name = "Vgr_Mothership",                    -- Another ship entry
            numRadii = 0,                   
            radii =
            {
                {fRange = 1000, fDamage = 1000},        -- This will deal 7000 damage within 1 km, as the Vgr_Mothership's sobDieTime is 7
                {fRange = 2000, fDamage = 200 },        -- This will deal an additional 1400 within 2 km
                {fRange = 4000, fDamage = 100 },        -- This will deal an additional 700 within 4 km
            },                                          -- So ships within 1 km will lose a total of 9100 health
        },
    }
    
    iTotalShips = 0                                         -- Initiating a global variable, to count ships into. Don't set this manually
    
    function initExplDamage()
    
        print("In initExplDamage()\n")
    
        --START OF SHIP NUMBER CHECKING SECTION
    
        local iTempEntryCount = 0                           -- This is used to count the actual number of ships
        repeat
            iTempEntryCount = iTempEntryCount + 1
        until (not ExplosionsTable[iTempEntryCount + 1])    -- Loop through all. When the next one is nil (false), you have the exact number of 
    
    entries
    
        print(" Counting ships: "..iTempEntryCount.." in total\n")
        iTotalShips = iTempEntryCount                       -- Set the global variable
    
        --END OF SHIP NUMBER CHECKING SECTION
        
        --START OF RADII CHECKING SECTION
    
        for iShipEntry = 1, iTotalShips do                  -- This is used to count the actual numbers of radii
    
            iTempEntryCount = 0                             -- Resetting the previously used local variable
            repeat
                iTempEntryCount = iTempEntryCount + 1       -- Loop through all. When the next one is nil (false), you have the exact number of 
    
    entries
            until (not ExplosionsTable[iShipEntry].radii[iTempEntryCount + 1])
    
            print(" "..ExplosionsTable[iShipEntry].name.." has "..iTempEntryCount.." damage radii\n")
            ExplosionsTable[iShipEntry].numRadii = iTempEntryCount -- Set the global variable
        end
        
        --END OF RADII CHECKING SECTION
    
        print("Initiating Tabular Explosion Damage, with "..iTotalShips.." ships\n")
        
        Rule_AddInterval("LoopThroughExplosionTable", 1)
    end
    
    function implementExplDamage(sSobGroup, tDamageTable)          -- This function takes the table that lists damage and radii for that ship
        
        if (SobGroup_HealthPercentage(sSobGroup) <= 0) then        -- If the ship's dying, do some damage
            print ("  A ship \""..tDamageTable.name.."\"is exploding!!\n")
            for iPlayerIndex = 0, Universe_PlayerCount() - 1 do    -- Go through every player to do damage to
                if (Player_IsAlive(iPlayerIndex) == 1) then        -- If that player is still alive,
                
                    for iDamageEntry = 1, tDamageTable.numRadii do -- Go through every level of damage, as listed in the table
                                                                   -- And do damage to all player's ships in proximity
                        SobGroup_DoDamageProximitySobGroup(sSobGroup, iPlayerIndex, tDamageTable.radii[iDamageEntry].fDamage, 
    
    tDamageTable.radii[iDamageEntry].fRange)
                        --print ("   Doing "..tDamageTable.radii[iDamageEntry].fDamage.." damage to all player "..iPlayerIndex.." ships, at 
    
    "..tDamageTable.radii[iDamageEntry].fRange.." metres\n")
                    end
                end
            end
        end
    end
    
    function LoopThroughExplosionTable() 
    
        --print ("In LoopThroughExplosionTable()\n")
        Update_AllShips()
        SobGroup_Create("TempRuntimeSobGroup")
        SobGroup_Clear("TempRuntimeSobGroup")
    
        for iPlayerIndex = 0, Universe_PlayerCount() - 1 do                  -- Go through every player
        
            if (Player_IsAlive(iPlayerIndex) == 1) then                      -- Don't bother for dead players
            
                for iTableEntry = 1, iTotalShips do                          -- Go through all the ship entries
        
                    local shipName = ExplosionsTable[iTableEntry].name       -- Inititate the ship's name to the appropriate entry in the table
    
                    Player_FillShipsByType("TempRuntimeSobGroup", iPlayerIndex, shipName) -- Get all ships of that ype
                    local numShips = SobGroup_Count("TempRuntimeSobGroup")                -- Count them
                    
                    if (numShips > 0) then
                        --print (" Player "..iPlayerIndex.." has "..numShips.." ships of type "..shipName.."\n")
                    end
                    
                    if (numShips == 0) then                                  -- Do nothing
                    
                    elseif (numShips == 1) then                              -- If 1 ship, don't need to split SobGroups
                    
                        implementExplDamage("TempRuntimeSobGroup", ExplosionsTable[iTableEntry])
                        
                    elseif (numShips == 2) then                              -- If 2 ships, SplitGroup won't work, only SplitGroupReference
                    
                        --print(" 2 ships, so using SplitGroupReference")
                        local numGroups = SobGroup_SplitGroupReference("sRuntimeGroup2", "TempRuntimeSobGroup", "AllShips", numShips)
                        for iShipIndex = 0, numGroups - 1 do
                            if (SobGroup_Count("sRuntimeGroup2"..iShipIndex) == 1) then
                                implementExplDamage("sRuntimeGroup2"..iShipIndex, ExplosionsTable[iTableEntry])
                            else
                                print(" [SobGroup Splitting of "..SobGroup_Count("sRuntimeGroup2"..iShipIndex).." of Player "..iPlayerIndex.."'s 
    
    "..numShips.." "..shipName.."'s failed. Skipping]")
                            end
                        end
                        
                    elseif (numShips ~= 0) then                              -- Split groups, if not 0 ships (in which case, skip)
    
                        local numGroups = SobGroup_SplitGroup("sRuntimeGroup2", "TempRuntimeSobGroup", numShips)
            
                        for iShipIndex = 0, numGroups - 1 do
                            if (SobGroup_Count("sRuntimeGroup2"..iShipIndex) ~= 1) then    -- If it hasn't split completely, try again with 
    
    SplitGroupReference
                                print(" [Basic Splitting of "..SobGroup_Count("sRuntimeGroup2"..iShipIndex).." of Player "..iPlayerIndex.."'s 
    
    "..numShips.." "..shipName.."'s failed. Using SplitGroupReference]")
                                local numGroups2 = SobGroup_SplitGroupReference("sRuntimeGroup3", "sRuntimeGroup2"..iShipIndex, "AllShips", 
    
    numShips)
    
    
    
    
    
    
    
    function SobGroup_SplitGroup(SobGroupOut, SobGroupToSplit, NumberToSplit)
        -- function created by Apollyon470
        local index = 0
        local distance = 0
        local bool = 0
        local SobNum = 0
        SobGroup_Create("TempSobGroup")
        SobGroup_Clear ("TempSobGroup")
        SobGroup_Create("TempSobGroup1")
        SobGroup_Clear ("TempSobGroup1")
        SobGroup_SobGroupAdd ("TempSobGroup", SobGroupToSplit)
        if ( SobGroup_Empty (SobGroupToSplit) == 1 ) then
            return 0
        end
        if ( NumberToSplit > SobGroup_Count(SobGroupToSplit) ) then
            NumberToSplit = SobGroup_Count(SobGroupToSplit)
        end
        while (index < NumberToSplit ) do
            bool = 0
            -- in the interests of resource saving, we start with a search band of 625
            interval = 625
            while (bool == 0) do
                distance = distance + interval
                -- something went wrong.  Please tell me, or have a go at fixing it yourself.
                if (interval > 3000000) then
                    bool = 1
                    return SobNum
                end
                SobGroup_FillProximitySobGroup ("TempSobGroup1", "TempSobGroup", SobGroupToSplit, distance)            
                if (SobGroup_Empty("TempSobGroup1") == 1)then
                    -- get the next interval
                else
                    if (SobGroup_Count("TempSobGroup1") > 1) then
                        -- too many ships, reduce interval
                        if (interval <= .2) then
                            -- Screw it! chunk 'em all in the same sobgroup
                            SobGroup_Create(SobGroupOut .. tostring(SobNum))
                            SobGroup_Clear (SobGroupOut .. tostring(SobNum))
                            SobGroup_SobGroupAdd (SobGroupOut .. tostring(SobNum), "TempSobGroup1")
                            SobGroup_Create("tempsob")
                            SobGroup_FillSubstract("tempsob", "TempSobGroup", SobGroupOut .. tostring(SobNum))
                            SobGroup_Clear ("TempSobGroup")
                            SobGroup_SobGroupAdd ("TempSobGroup", "tempsob")
                            bool = 1
                        else
                            distance = distance - interval
                            interval = interval / 5
                        end
                    else
                        -- we got one! add it to the list!
                        SobGroup_Create(SobGroupOut .. tostring(SobNum))
                        SobGroup_Clear (SobGroupOut .. tostring(SobNum))
                        SobGroup_SobGroupAdd (SobGroupOut .. tostring(SobNum), "TempSobGroup1")
                        SobGroup_Create("tempsob")
                        SobGroup_FillSubstract("tempsob", "TempSobGroup", SobGroupOut .. tostring(SobNum))
                        SobGroup_Clear ("TempSobGroup")
                        SobGroup_SobGroupAdd ("TempSobGroup", "tempsob")
                        bool = 1
                    end
                end            
            end
            index = index + SobGroup_Count(SobGroupOut .. tostring(SobNum))
            SobNum = SobNum + 1
        end
        return SobNum
    end
    
    function SobGroup_SplitGroupReference(SobGroupOut, SobGroupToSplit, ReferenceSobGroup, NumberToSplit)
        -- function created by Apollyon470
        local index = 0
        local distance = 0
        local bool = 0
        local SobNum = 0
        SobGroup_Create("TempSobGroup")
        SobGroup_Clear ("TempSobGroup")
        SobGroup_Create("TempSobGroup1")
        SobGroup_Clear ("TempSobGroup1")
        SobGroup_SobGroupAdd ("TempSobGroup", SobGroupToSplit)
        if ( SobGroup_Empty (SobGroupToSplit) == 1 ) then
            return 0
        end
        if ( NumberToSplit > SobGroup_Count(SobGroupToSplit) ) then
            NumberToSplit = SobGroup_Count(SobGroupToSplit)
        end
        while (index < NumberToSplit ) do
            bool = 0
            -- in the interests of resource saving, we start with a search band of 625
            interval = 625
            while (bool == 0) do
                distance = distance + interval
                -- something went wrong.  Please tell me, or have a go at fixing it yourself.
                if (interval > 3000000) then
                    bool = 1
                    return SobNum
                end
                SobGroup_FillProximitySobGroup ("TempSobGroup1", "TempSobGroup", ReferenceSobGroup, distance)            
                if (SobGroup_Empty("TempSobGroup1") == 1)then
                    -- get the next interval
                else
                    if (SobGroup_Count("TempSobGroup1") > 1) then
                        -- too many ships, reduce interval
                        if (interval <= .2) then
                            -- Screw it! chunk 'em all in the same sobgroup
                            SobGroup_Create(SobGroupOut .. tostring(SobNum))
                            SobGroup_Clear (SobGroupOut .. tostring(SobNum))
                            SobGroup_SobGroupAdd (SobGroupOut .. tostring(SobNum), "TempSobGroup1")
                            SobGroup_Create("tempsob")
                            SobGroup_FillSubstract("tempsob", "TempSobGroup", SobGroupOut .. tostring(SobNum))
                            SobGroup_Clear ("TempSobGroup")
                            SobGroup_SobGroupAdd ("TempSobGroup", "tempsob")
                            bool = 1
                        else
                            distance = distance - interval
                            interval = interval / 5
                        end
                    else
                        -- we got one! add it to the list!
                        SobGroup_Create(SobGroupOut .. tostring(SobNum))
                        SobGroup_Clear (SobGroupOut .. tostring(SobNum))
                        SobGroup_SobGroupAdd (SobGroupOut .. tostring(SobNum), "TempSobGroup1")
                        SobGroup_Create("tempsob")
                        SobGroup_FillSubstract("tempsob", "TempSobGroup", SobGroupOut .. tostring(SobNum))
                        SobGroup_Clear ("TempSobGroup")
                        SobGroup_SobGroupAdd ("TempSobGroup", "tempsob")
                        bool = 1
                    end
                end            
            end
            index = index + SobGroup_Count(SobGroupOut .. tostring(SobNum))
            SobNum = SobNum + 1
        end
        return SobNum
    end
    
    
    
    
    function Update_AllShips()
    
        SobGroup_Create("AllShips")
        SobGroup_Clear("AllShips")
        
        for iPlayerIndex = 0, Universe_PlayerCount() - 1 do
            if (Player_IsAlive(iPlayerIndex) == 1) then
                SobGroup_SobGroupAdd("AllShips", "Player_Ships"..iPlayerIndex)
            end
        end
    
    end 
    Last edited by adamstrange; 20th Dec 09 at 1:46 AM.

  19. #19
    Member Dim@'s Avatar
    Join Date
    Jul 2007
    Location
    Battlecruiser complete
    First of all, can you, in future, post your code in "CODE" tags, not "QUOTE" tags? Because the quote gets rid of all your indentations, and takes up too much space. Code, on the other hand, is very carefyul not to wrap code, to leave the indents, and, finally, limits it to a certain height, adding scrollbars.

    Secondly, can you post your Hw2.log?

    And by "My game won't even start" you mean it doesn't get to the main menu?

  20. #20
    Hey Dim,I got it to work.

    The problem was that I'm using Opera and when I copied the code it didn't copy the entire code.

    No how could I set this so that it works on shipyards,carriers and destroyers ?
    Last edited by adamstrange; 20th Dec 09 at 2:06 AM.

  21. #21
    Member Dim@'s Avatar
    Join Date
    Jul 2007
    Location
    Battlecruiser complete
    You simply have to edit the table at the top, the one named "ExplosionsTable".

    There are more detailed instructions in the first post, but basically add ship entries to it, so they match the old ones (this shouldn't be new to you, like copying build and research items, then modifying, to make new ones).

    Once you have made a copy of an existing one, modify the values. Change the name to to the name of the ship you want it to work with, and add or remove the parts of the radii section, altering the fDamage and fRange each time.

    Also, don't forget that the damage is per second, not once during the explosion.

    EDIT: Note that I am already working on the next version. Having taken a look at the Complex Mod scripts, seeing how they did it, I am now writing the function to do the damage once, at the exact right time (during the final, bright, explosion).

  22. #22
    Member mickey's Avatar
    Join Date
    Mar 2008
    Location
    Moscow
    Quote Originally Posted by User Name
    EDIT: Note that I am already working on the next version. Having taken a look at the Complex Mod scripts, seeing how they did it, I am now writing the function to do the damage once, at the exact right time (during the final, bright, explosion).
    !!!!!!!!!!!!!!!!!!!! Successful work to you! It that is necessary !!!!!!!!!!!!!!!!!!!

  23. #23
    Dim I just thought of something and you can tell me if this is possible.
    My question is related to this comment...
    Also, don't forget that the damage is per second, not once during the explosion.
    Since your working on the damage being done once,upon the exact time that the ship is destroyed,is it possible to set the script to do both ?

    The final explosion causes the initial damage but,over a slower time rate,causes additional damage.

    What I'm getting at is that this slower time rate acts as a blast wave so that a ship right next to an exploding MS receives the initial damage upon detonation [call it ZERO TIME] but a ship a mile away would receive some of this damage [call it DAMAGE TIME RADIUS] 5 TO 10 seconds later.

    I'm thinking that if this is possible,I could try to create a blast wave ring effect that spreads out over time when a MS or SY is destroyed.

    One thing though that I don't understand.

    You said that the current explosion is in time and not instant but if you give a ship a slightly higher rate damage rates it almost seems to work instantly,for example...

    I gave the Hgn Carrier this setting-
    {fRange = 1000, fDamage = 700},
    {fRange = 2000, fDamage = 400},


    I then placed 3 Scouts at these 3 different ranges, 200,700 & 1500.

    I then detonated it and the Scout at the 200 range vaporized instantly but the other exploded about a quarter of a second later.

    In a second test I moved the Carrier near the MS and detonated it.

    It did a tiny amount of damage to it but a Resource Collector exactly at a range of 2000 must have had a least 97 percent damage done to it.

    I may have to play around with these settings though to see how the game plays out.
    Last edited by adamstrange; 20th Dec 09 at 12:36 PM.

  24. #24
    Member Dim@'s Avatar
    Join Date
    Jul 2007
    Location
    Battlecruiser complete
    So, your idea is basically to have not only multiple damage radii, but also multiple groups of damage radii that occur at different times?

    That is possible, but I am not sure how possible it is to have this damage occur AFTER the ship disappears. Once a ship has finished dying (i.e. the explosions are done, and it actually disappears off the map), there is no longer any way to know where it was, it disappears from every sobGroup, so you can no longer use "SobGroup_DoDamageProximitySobGroup()".

    The only way I can see this being done is to spawn a dummy ship in its place, and do damage from that...but that would be quite bulky code, not to mention requiring you to create such a dummy ship...

    I can also say that the "one time" explosion damage, based on Complex, now appears to work, though I am not ready to post it yet (especially if I might be adding other groups of damage radii).

    As for your test, how much health does a scout have? I would expect that the damage is done to every member of the squadron simultaneously, and they probably don't have more than about 30 health. So, 700 health per second is enough to kill it instantly.

    With the resource collector it is probably the same, as the mothership has 200,000 health, and you were only doing about 4000. Meanwhile, the resource collector has 2000, and it was getting 1600 damage, or so.

  25. #25
    There is no way to make those damage affected by the ships armor type?

    Since a heavy stuff is more tough and robust than a tiny scout with tiny weak exposed mechanic.

  26. #26
    The Scout has a maxhealth = 30

    This from the vanilla HW2.

  27. #27
    Member Dim@'s Avatar
    Join Date
    Jul 2007
    Location
    Battlecruiser complete
    There is no way to make those damage affected by the ships armor type?
    Nope, short of rewriting the whole SobGroup_DoDamageProximitySobGroup() function. And I wouldn't do that because if you rewrite it, it will be a lot slower, as the current one is hardcoded, and doesn't have to go through the whole lua interpreting thing.

    Even the Complex Mod didn't bother doing that.

    Not that it isn't possible, mind you. To rewrite the function...

  28. #28
    Member Dim@'s Avatar
    Join Date
    Jul 2007
    Location
    Battlecruiser complete
    Updated to Version 2.0 (I thought the number deserved a major increase).

    It will now do damage at an exact time, specified by you, rather than per second. I had to have a look at the Complex Mod scripts, to see how they did it, and then reapplied a similar principle to one function for all, rather than for each ship. (Most importantly, using Wait_Start() instead of Rule_AddInterval() for the "timing" functionality)

    I have decided that this will be the last update (or maybe second last, if I have to fine-tune anything).

    The reason for this is that the only way to go forward is to add more than one fDeathTime, with multiple radii for each, or to add the ability to continue to cause damage after the ship dies (like a radioactive cloud, left in the wake of a the enormous explosion).

    The first one is slightly redundant (from what I understand, it is only wanted to cause damage after ship death, which is a completely different idea). In addition, it will also take bulkier code, and longer execution time (lower performance), for something that is really quite unnecessary (there is ONE big explosion, so ONE wave of damage). A spreading ring of damage wouldn't work either, as ships close by would get damaged too, with later waves.

    The second one is difficult. I will continue to work on the idea with mickey, and will share our results with others who are interested, but it has no place here. It will require lots of code, and generally things that will defeat the purpose of this.

    After all, the point of this script was to provide an easy, compact solution to anyone who wanted to give their cap ships explosion damage, without having to understand it fully, or having to write a function for every ship. It is a general script. The two above are specialisations that most people don't need. Both of them are possible, but they should be done by a different script. Not this one.

  29. #29
    Member mickey's Avatar
    Join Date
    Mar 2008
    Location
    Moscow

    Updating to version 2.0

    Waaaaau!!! You the surprising wizard!!!!!!!!!!
    Thanks huge to you! You have made very much for moding HOMEWORLD2!!!!!!!!!!
    Now for Hiigaran and Vaygr race it perfectly works!!!
    Last edited by mickey; 21st Dec 09 at 6:36 AM.

  30. #30
    or to add the ability to continue to cause damage after the ship dies (like a radioactive cloud, left in the wake of a the enormous explosion).
    This would make for a perfect superweapon,The Nebula Generator.

    If this can be coded into a missile you can fire it into an enemy's resource operation.

    Once it detonated it would release radiation that would start to destroy any collectors and controllers and would last for about 5 minutes thus deny the enemy of vital RU's.

  31. #31
    Member Dim@'s Avatar
    Join Date
    Jul 2007
    Location
    Battlecruiser complete
    Actually, my idea was more along the lines of spawning a dummy ship, possibly using the hod of a nebula, and then using SobGroup_DoDamageProximitySobGroup() every second on it. It would be harder with a missile.

    Perhaps you could use more of a "Complex" Juggernaut type thing that you drive into a resource operation, and then scuttle...

    EDIT: Or even ... a PROBE, that, once deployed, constantly generates a radiation field ( SobGroup_DoDamageProximitySobGroup() )?

  32. #32
    Hey Dim, is it possible to add a code into this script so that when a ship is about to blow up,other ships automatically move away from it ?

    I've adden this code to the other Capitals and when I destroy and enemy Carrier or BC it also destroys my attacking ships [well except for Frigates].

  33. #33
    Member Dim@'s Avatar
    Join Date
    Jul 2007
    Location
    Battlecruiser complete
    Perhaps, though you may be better off with doing it with AI.
    I won't be writing this here, though. As I said, this is a general script.

  34. #34
    Just make the "damage income timer" larger. Since Dim have make that possible in one of it latest update.

  35. #35
    I have the latest version and damage income timer does not appear in the code.

    Could this have another name ?

  36. #36
    Probably, i havn't seen the code ^^, it was just words for you to understand what i was speaking about :P .
    Sry for the inconvenience.

  37. #37
    I have been attempting to code in an on/off switch for the explosion damage as a game option, but keep getting stack traceback errors. Can anyone make sense of this?

    From gamesetupoptions.lua
    Code:
    	{
    		name = "explosions",
    		locName = "Ship Explosion Damage",
    		tooltip = "Frigate and Capital ship explosions cause damage to nearby ships",
    		default = 0,
    		visible = 1,
    		choices = 
    		{
    			"Disabled",
    			"off",
    			"Enabled",
    			"on",
    		},
    	},
    From deathmatch.lua
    Code:
    function SetExplosionDamageFromOption()
    	local ShipExplosionDamage = GetGameSettingAsString("explosions")
    	local DamageScript = "off"
    	do
    		if (explosions == on) then
    			DamageScript = initExplDamage()
    			else
    			DamageScript = "off"
    		end
    	print("Ship Explosion Damage set to " .. ShipExplosionDamage)
    	SetExplosionDamageFromOption(DamageScript)
    	end
    end
    Function OnInit() has this line in it that is referring to the damage scripts.

    SetExplosionDamageFromOption()


    From the HW2.log
    Code:
    Cannot overwrite function SobGroup_SplitGroup
    Cannot overwrite function SobGroup_SplitGroupReference
    
    ---------- This part is repeated about 100x ---------------
    In initExplDamage()
     Counting ships: 2 in total
     Ship1 has 2 damage radii, and an fDeathTime of 6.5
     Ship2 has 3 damage radii, and an fDeathTime of 6.5
    Initiating Tabular Explosion Damage, with 2 ships
    Ship Explosion Damage set to on
    -----------------------------------------------------------
    
    
    parameter: stack overflow
    stack traceback:
    1: function `tostring' [C]
    2: function `print' [C]
    3: function `initExplDamage' at line 45 [string ""]
    4: function `SetExplosionDamageFromOption' at line 115 [String ""]
    5: function `SetExplosionDamageFromOption' at line 120 [String ""] <--this line is the same X amount of times as well

  38. #38
    Member Dim@'s Avatar
    Join Date
    Jul 2007
    Location
    Battlecruiser complete
    That function is recursive, for no apparent reason.

    SetExplosionDamageFromOption(DamageScript)

    It calls itself. Each time it does, another copy of the script is added to memory (or at least a reference to it). Eventually the Stack overflows, memory runs out.

    It should probably be something like this:
    Code:
    function SetExplosionDamageFromOption()
        if (GetGameSettingAsString("explosions") == "on") then
            print("Ship Explosion Damage set to ON")
            initExplDamage()
        else
            print("Ship Explosion Damage set to OFF")
        end
    end
    Also, note this part:
    Cannot overwrite function SobGroup_SplitGroup
    Cannot overwrite function SobGroup_SplitGroupReference
    Looks like you have already used these functions, added them to your (previous?) scripts.

  39. #39
    Thanks for sorting that repeating problem out for me.

    For the part where the functions are 'already there', they are included but shouldn't be activated unless the explosion damage is turned on. As far as I can tell, its just the log reading all listed scripts in the deathmatch.lua whether they are active or not.

  40. #40
    Hey Dim,are you updating this script so that the damage is caused exactly at the time of the bright light ?

    Right now the ship receive damage before the final explosion.

  41. #41
    Member Dim@'s Avatar
    Join Date
    Jul 2007
    Location
    Battlecruiser complete
    Um, it already does that.

    You just have to set the right fDeathTime value, and remember, it will only be accurate to the sum of fDeathCheckRate and fTimerCheckRate.

  42. #42
    I am trying to add a ship to the code, but it causes my game to lag

    Error Lua
    [Advanced Splitting failed. Skipping]
    [Basic Splitting of 5 of Player 0's 120 vgr_FighterKamikazes's failed. Using SplitGroupReference]
    [Advanced Splitting failed. Skipping]
    [Basic Splitting of 5 of Player 0's 120 vgr_FighterKamikazes's failed. Using

    .... And it goes for ever

    i added the ship like this ... it is identical has the other ones but for some reason, it doesn't work
    { name = "vgr_FighterKamikazes",
    numRadii = 0,
    fDeathTime = 0.5,
    radii =
    { {fRange = 50, fDamage = 5000}, }, },

  43. #43
    Member Dim@'s Avatar
    Join Date
    Jul 2007
    Location
    Battlecruiser complete
    Is that ship in a squadron?

    This won't work for ships in squadrons, because SobGroup_SplitGroup won't work for ships in squadrons. And that won't work because ships in a squadron have a single location, but count as more than one ship.

  44. #44
    Hey Dim,what about applying this script to subsystems ?

    Would be cool for Capital Production subsystems like those on the shipyard to cause damage when destroyed.

  45. #45
    Member Dim@'s Avatar
    Join Date
    Jul 2007
    Location
    Battlecruiser complete
    That is probably possible...

    But not here.

    This is a finished script.

  46. #46
    Dim can you explain this to me...

    If I set a ship's damage to {fRange =3000 is the range the same in Meters & Kilometers thats found in the game ?

    Like when you give a ship orders to move you see the value of the distance in red...is this the same ?

    Also I add the Resource Controller into the code and gave it these settings

    Code:
    name = "Hgn_ResourceController",                    
            numRadii = 0,                               
            fDeathTime = 4.5,                           
            radii =                                     
            {
                {fRange = 500,  fDamage = 10000},      
                {fRange = 800,  fDamage = 800 },
                {fRange = 1000,  fDamage = 200},
    But no matter what values I give it,it doesn't cause any damage.
    Last edited by adamstrange; 4th Mar 10 at 5:59 PM.

  47. #47
    Member ajlsunrise's Avatar
    Join Date
    Jun 2008
    Location
    Binaryland
    adam: to requote dim@ (emphasis added):
    Quote Originally Posted by Dim@
    As an example, if you have a ship that has a sobDieTime of 5 seconds, and you want all ships in 500 metres to take 1500 Damage, and 1 km to take 500 damage, one second before death, you will need to create two radii. The inner one should have an fRange of 500, and an fDamage of 1000. This will give all inner ships 1000 damage. The outer radius should have an fRange of 1000, and an fDamage of 500. This will give inner ships an additional 500 damage (for a total of 1500), and outer ships 500. fDeathTime should be set to 4.
    If the ship were named Hgn_NewShip, the table entry would look like this:
    Code:
    {
    name = "Hgn_NewShip",
    numRadii = 0,
    fDeathTime = 4,
    radii =
        {
            {fRange = 500, fDamage = 1000},
            {fRange = 1000, fDamage = 500},
        },
    },

  48. #48
    Member Dim@'s Avatar
    Join Date
    Jul 2007
    Location
    Battlecruiser complete
    Yeah, those numbers correspond to in-game meters.

    And the ResourceController doesn't work because fDeathTime must be smaller than the sobDieTime of the ship. AND it must be smaller by more than the sum of fDeathCheckRate and fTimerCheckRate.
    The sobDieTime of Hgn_ResourceController is 1. So 4.5 is too large. The ship no longer exists, and damage cannot be applied around it.

  49. #49
    Member ajlsunrise's Avatar
    Join Date
    Jun 2008
    Location
    Binaryland
    so fDeathTime < (sobDieTime - fDeathCheckRate - fTimerCheckRate)

  50. #50
    Member Dim@'s Avatar
    Join Date
    Jul 2007
    Location
    Battlecruiser complete
    Yes, exactly.

    And you can adjust all of those.

Page 1 of 2 12 LastLast

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

     

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •