Tamkis' Lua help thread

Status
Not open for further replies.

Tamkis

Lua Grasshopper
How would one go about using environmental Objects (such as flames, Metal Sonic's energyball, etc) as proper player missiles that don't self-inflict the player using P_SpawnMissile(), and which increment the launching player's score upon collision with an opponent? For some reason, using this function with some objects don't self-inflict the player and do update the score, while others do self-inflict and don't update the score. I have also tried changing the launched object's object flags by desiginating them with a MF_MISSILE flag with no luck.

I am trying to make a lua script that replaces the vanilla ring weapons with other objects. Also, how would one go about decrementing the weapon's counter by only 1 on usage (mine for some reason decrements by 2), and in displaying custom hurt messages?

Attached is my in-progress script. Metal Sonic's energy ball and the Brak Napalm Bomb are not functioning as proper missiles.

Code:
//New weapons
//v1.0 By Tamkis

//Replaces current weapons with 6 new ones
//Weapon ammo is removed, and all weapon usage
//decrement weapon count by 2
//Energy Ball and Cannonball launcher are defensive
//weapons, don't change player scores

//Napalm bomb is partially defensive (updates score when physically hit by bomb
//but not by flames

//Updates F1 Multiplayer weapons screen with new weapon info
//Known bugs: Double decremntation of wepaons usage. "Feature" not bug.
//HurtMsgs don't display properly. (Creates "[guy] hit [guy]"]. Just wanted to remove
//old HurtMsgs, so feature not bug

//Remove all ammos
addHook("MapLoad", do
    //Hide me mobjinfo stats
    local hideme = {
        spawnstate = S_INVISIBLE,
        flags = MF_NOBLOCKMAP|MF_NOSECTOR
    }
    
    //List of standard thrown weapons and pickups to disable
    local list = {
        MT_BOUNCERING,
        MT_RAILRING,
        MT_AUTOMATICRING,
        MT_EXPLOSIONRING,
        MT_SCATTERRING,
        MT_GRENADERING
    }    
    for _,i in ipairs(list) // for every mobjtype in the list
        for k,v in pairs(hideme)
            mobjinfo[i][k] = v // add the properties in hideme to mobjinfo
        end
    end
end)

addHook("MapChange", do
    //Hide me mobjinfo stats
    local hideme = {
        spawnstate = S_INVISIBLE,
        flags = MF_NOBLOCKMAP|MF_NOSECTOR
    }
    
    //List of standard thrown weapons and pickups to disable
    local list = {
        MT_BOUNCERING,
        MT_RAILRING,
        MT_AUTOMATICRING,
        MT_EXPLOSIONRING,
        MT_SCATTERRING,
        MT_GRENADERING
    }    
    for _,i in ipairs(list) // for every mobjtype in the list
        for k,v in pairs(hideme)
            mobjinfo[i][k] = v // add the properties in hideme to mobjinfo
        end
    end
end)

//Perform everyframe
addHook("ThinkFrame", do

    //Cycle through all players
    for player in players.iterate do

        //Check if player is tapping and toggle flags as appropriately, NOT holding
        //See http://wiki.srb2.org/wiki/Lua/Custom_player_ability#Triggers_on_button_press
        //for more info
        
        //Remove any invice from weps on jump
        if (player.cmd.buttons & BT_JUMP)
            player.powers[pw_flashing]=0
        end
        
        if not (player.cmd.buttons & BT_ATTACK) then //BT_ATTACK=ring launch button
            player.tapready = true
            player.tapping = false
        elseif player.tapready then
            player.tapping = true
            player.powers[pw_flashing]=0    //Disable any temp invince due to weapons
            player.tapready = false
        else
            player.tapping = false
        end

        //Laser Turret
        //If current weapon is Auto ring and BT_ATTACK is HELD
        if (player.currentweapon==WEP_AUTO) and (player.cmd.buttons & BT_ATTACK)
            if (player.health>1)    //If have enough rings
                //Spawn a Turret Laser
                P_SpawnPlayerMissile(player.mo, MT_TURRETLASER, MF2_AUTOMATIC)
                player.powers[pw_automaticring]=$1-1
            end
        end

        //Cannonball Launcher
        //If current weapon is Bounce ring and BT_ATTACK is tapped
        if (player.currentweapon==WEP_BOUNCE) and (player.tapping==true)
            if (player.health>1)                //If have enough rings
                player.powers[pw_flashing]=105    //Give 3 secs of invince
                
                //Spawn a Cannonball Launcher, give it a fuse of 30 secs
                local mobj    //Mobj
                mobj=P_SpawnPlayerMissile(player.mo, MT_CANNONLAUNCHER, MF2_BOUNCERING)
                mobj.fuse=1050
                
                //Spawn a flame at usage point, give it a fuse of 30 secs
                mobj=P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z, MT_FLAME)
                mobj.fuse=1050
                
                //Decrement 1 from wep counter every tap. (This usually results in lose of 2 weps
                player.powers[pw_bouncering]=$1-1
            end
        end
    
        //Arrow
        //If current weapon is Rail Ring and BT_ATTACK is tapped
        if (player.currentweapon==WEP_RAIL) and (player.tapping==true)    
            if (player.health>1)    //If have enough rings
                //Spawn an Arrow
                P_SpawnPlayerMissile(player.mo, MT_ARROW, MF2_RAILRING)
                //Decrement 1 from wep counter every tap. (This usually results in lose of 2 weps
                player.powers[pw_railring]=$1-1    
            end
        end
    
        //Large Napalm Bomb
        //If current weapon is Grenade and BT_ATTACK is tapped        
        if (player.currentweapon==WEP_EXPLODE) and (player.tapping==true)
            if (player.health>1)    //If have enough rings
                //Spawn large napalm bomb
                P_SpawnPlayerMissile(player.mo, MT_CYBRAKDEMON_NAPALM_BOMB_LARGE, MF2_EXPLOSION)
                //Decrement 1 from wep counter every tap. (This usually results in lose of 2 weps
                player.powers[pw_explosionring]=$1-1
            end
        end

        //Energy Ball
        //If current weapon is Scatter and BT_ATTACK is tapped
        if (player.currentweapon==WEP_SCATTER) and (player.tapping==true)
            if (player.health>1)    //If have enough rings
                player.powers[pw_flashing]=25    //Give 0.7 secs of invince
                //Spawn Energy ball, give it a fuse of 10 secs
                local mobj    //Mobj
                mobj=P_SpawnPlayerMissile(player.mo, MT_ENERGYBALL, MF2_SCATTER)
                mobj.fuse=350
                //Decrement 1 from wep counter every tap. (This usually results in lose of 2 weps
                player.powers[pw_scatterring]=$1-1
            end
        end

        //Brak Missile
        //If current weapon is Grenade, and if tapping
        if (player.currentweapon==WEP_GRENADE) and (player.tapping==true)
            if (player.health>1)    //If have enough rings
                //Spawn Brak Missile
                P_SpawnPlayerMissile(player.mo, MT_CYBRAKDEMON_MISSILE, MF2_RAILRING)
                //Decrement 1 from wep counter every tap. (This usually results in lose of 2 weps
                player.powers[pw_grenadering]=$1-1
            end
        end
    end    

    //Hide me mobjinfo stats
    local hideme = {
        spawnstate = S_INVISIBLE,
        flags = MF_NOBLOCKMAP|MF_NOSECTOR
    }
    
    //List of standard thrown weapons and pickups to disable
    local list = {
        MT_THROWNBOUNCE,
        MT_SPARK,
        MT_THROWNAUTOMATIC,
        MT_THROWNEXPLOSION,
        MT_THROWNSCATTER,
        MT_THROWNGRENADE,
    }

    for _,i in ipairs(list) // for every mobjtype in the list
        for k,v in pairs(hideme)
            mobjinfo[i][k] = v // add the properties in hideme to mobjinfo
        end
    end
end)

//Fuse handler
addHook("MobjFuse", function(mobj)

    //List of custom wepaons that use Fuse
    local list = 
    {
        MT_ENERGYBALL,
        MT_CANNONLAUNCHER,
        MT_CANNONBALL,
        MT_FLAME
    }

    //If mobj is valid and is NOT a player
    if (mobj.valid==true) and (mobj.mobjtype!=MT_PLAYER)
        for _,i in ipairs(list) // for every mobjtype in the list
                //If mobj type is in the list and is NOT a player, remove it
                if (mobj.mobjtype==list[i]) and (mobj.mobjtype!=MT_PLAYER)
                    if (mobj.valid)
                        P_RemoveMobj(mobj)
                    end
                end
        end
    end
end)

//Custom Hurt messages.
addHook("HurtMsg", function(player, inflictor, source)

    //Parallel arrays
    //Custom types of weapons
    local Types=
    {
        MT_ARROW,
        MT_CYBRAKDEMON_NAPALM_BOMB_LARGE,
        MT_CYBRAKDEMON_MISSILE,
        MT_TURRETLASER,
    }
    
    //Direct object
    local DirectObj=
    {
        "flung arrow",
        "lobbed Napalm bomb",
        "launched Brak missile",
        "shot laser",
    }

    //Verb
    local verb=
    {
        "stabbed",
        "obliterated",
        "decimated",
        "fried",
    }

    //Generate custom message based on wep type and if hurt vs. killed
    for _,i in ipairs(Types) // for every mobjtype in the list
        if (((inflictor) and (inflictor.type == Types[i])) and ((source) and (source.player))) then
            if player.mo.health then
                print(("%s's %s %s %s."):format(source.player.name, DirectObj[i], verb[i], player.name))
            else
                   print(("%s's %s defeated %s."):format(source.player.name, DirectObj[i], player.name))
            end
            return true
        end
    end
end)

Thanks in advance for the advice and bug fixes. I'll credit in the upcoming lua re-submission!
 
(Sorry in advanced for triple posting. I eventually gave up on the previous lua script. I figured I would change this thread's title from "Missile Lua help" to "Tamkis' Lua help thread", in order to serve as a generic Lua help thread for myself, instead of posting a new thread every time I have a different Lua issue.)

So I am currently wrapping up my Race HUD Lua script (finally) for an initial beta submission to releases so I can stop sitting on it and gitter done. The script shows the ranking of the top 5 racers (and Metal Sonic) in Race/Competition modes, showing the racer name and player icon on the left side of the screen. Basically, the Race HUD Lua script ranks players (and Metal Sonic) based on their lap and what starpost ID order number hit. To calculate the rank and other stats, I added custom variables to each gamer's player_t slot.

After testing the script online with a few players, we ran into a massive problem, perhaps even a bug, with the PlayerJoin Lua hook. For netgames, I attempt to initialize these custom variables with PlayerJoin to non-nil values. However, in a netgame, despite this attempt, the variables still never get initialized, and eventually, a Lua error of "attempting to compare a nil value" is thrown in the HUD_Rank drawing hook whenever a new player joins a race/competition round mid-match

Posted below is the relevant Lua code blocks, with code flow and problem areas bolded:

Code:
addHook("MapLoad",do
    ToggleMS()
    [B]InitRankAll()[/B]
    CountDown()
end)

addHook("PlayerJoin", function(player)
[B]    InitRank(player)    //Init the player's rank[/B]
end)

//Function initializes ranking vars for all players,
//including the amount of checkpoints
//players in the map, rankcnt, and rank, vars, etc for all players upon MapLoad
//Inputs:  None
//Outputs: None (initializes variables and all players stats)
local function InitRankAll()

    //(Init some global variable stuffs)
    
    [B]//Reset ALL player rank stats
    for player in players.iterate do
        //if ((player.mo) and (player.mo.valid))
            InitRank(player)
        //end
    end[/B]
end

//Function inits the rank of a single player
//Inputs: player_t
//Output: None (Initializes a player's ranking variables)
local function InitRank(player)
    //If player exists, do stuff
    
    //if (((player) and (player.mo)) and (player.mo.valid))
    //if ((player.mo) and (player.mo.valid))

        //Reset players' ranking stats
        player.rankcnt=0    //Rankcnt is a counter of amount of cumulative checkpoints hit
        player.rank=max        //Rank is actually the rank of player for icons (1st-5th etc)
        player.done=0        //No one has finished race yet
        player.fstate=0        //Finish state=unfinished
    //end
end

//Add hud_rank to HUD coroutine
hud.add(hud_rank)

local function hud_rank(v, stplyr)    

        //(INIT CODE)
        
        //Cycle through all players to display rank face icon/name
        for player in players.iterate do
            if (player.mo) and (player.mo.valid)
            
                //Get 1st 5 ranks
                //Get the players icon rank
[B]                local rank=player.rank    //ERROR!
                
                //@This IF condnitional caused an error spam when a new guy joins mid-race!
                //I think it is fixed
                if ((rank>=1) and (rank<=5))[/B]
                    local sk=player.mo.skin            //Get player skin name string
                    local hname=player.name            //Get player's username

           (OTHER STUFF)
end)
I attempt to circumvent the problem by initializing all of the custom ranking variables to all 32 player_t slots in the game with InitRankAll(), and then initialize the rank of new people who join with PlayerJoin.

I strongly believe the problem is due to the PlayerJoin hook:

Wiki:
PlayerJoin

Hook format: addHook("PlayerJoin", functionname)
Function format: function(int playernum)
Executes when a player joins. playernum is the node of the joining player. Note that the player (in this case, players[playernum]) is not actually in-game at the time this hook is called, and cannot be accessed.

So, how would I be able to access the player_t of joining players as a workaround, or at least lag the script until the player has joined and its var accesiable? The netvars hook would work, but it has been broken since 2.1.8
 
Status
Not open for further replies.

Who is viewing this thread (Total: 1, Members: 0, Guests: 1)

Back
Top