FAQ / issues
changelog
developers
history
contact
game-monitor.com
We apologize that the scripting tutorials have not been on time for a month now. Many of the QA members and MTA team are generally busy at this time of the year. We will try to continue giving you new scripting tutorials every week or as soon as possible.

This week's tutorial is how to make a King of the Hill gamemode. The example KOTH script here will monitor a zone (the hill) and give points to a person when they occupy it alone. Every second they remain in the zone, they recieve 1 point. After a certain time limit, the game is over and the person with the highest score wins.

thumbnail

Video footage: scriptvideo6.avi - DivX 5.0 (640x480, 29.97fps)
Forum support thread: forum.mtavc.com

King of the Hill Script: script6.lua

Preparation

At first we set up a timer that will check players location every 500 ms.

 
kothTimer = setTimer ( "checkHillArea", 500, 0 )
Then, when the resource is started we start the koth gamemode and create a square, the area which players will have to capture.
 
addEventHandler ( "onResourceStart", getRootElement(), "kothStart" )
function kothStart ( name )
     hillArea = createColSquare ( -2171.0678710938, 678.17950439453, 0, 15, 15 )
MTA:SA has the ability to create and manipulate San Andreas's gang radar areas, like you could see in single player. To create it we use createRadarArea ( X, Y, sizeX, sizeY, R, G, B, A, [ elements visible to ] )
 
     hillRadar = createRadarArea ( -2183.5678710938, 705.67950439453, 40, -40, 0,
 255, 0, 175 )
Then with a loop we create text displays (the way you learned it in the previous tutorial) which will show the leader and current points for every player. Set points to 0 for everyone with setElementData.
 
     local globalTextDisplay = textCreateDisplay ()
     textItemLeaderScore = textCreateTextItem ( "Leader: None", 0.15, 0.3, 0, 255,
 0, 0, 255, 1.4 )
     textDisplayAddText ( globalTextDisplay, textItemLeaderScore )
 
     for k,v in getElementsByType ( "player" ) do
          setElementData ( v, "points", 0 )
          local playerTextDisplay = textCreateDisplay ()
          local yourScore = textCreateTextItem ( "Score: "..getElementData(v, 
"points"), 0.15, 0.7, 0, 255, 0, 0, 255, 1.8 )
          textDisplayAddText ( playerTextDisplay, yourScore )
          textDisplayAddObserver ( playerTextDisplay, v )
          setElementData ( v, "textItemPoints", yourScore )
 
          textDisplayAddObserver ( globalTextDisplay, v )
          leaderPlayer = false
     end
And set a timer to finish the round in 5 minutes
 
     kothEndTimer = setTimer ( "kothEnd", 300000, 1 )
end
For every player who joins after the game mode is started we also have to set up the text displays and points.
 
addEventHandler ( "onPlayerJoin", getRootElement(), "kothJoin" )
function kothJoin ()
     setElementData ( source, "points", 0 )
     local playerTextDisplay = textCreateDisplay ()
     local yourScore = textCreateTextItem ( "Score: "..getElementData(source, 
"points"), 0.15, 0.7, 0, 255, 0, 0, 255, 1.8 )
     textDisplayAddText ( playerTextDisplay, yourScore )
     textDisplayAddObserver ( playerTextDisplay, source )
     setElementData ( source, "textItemPoints", yourScore )
     textDisplayAddObserver ( globalTextDisplay, source )
end
When a player spawns
 
addEventHandler ( "onPlayerSpawn", getRootElement(), "kothSpawn" )
function kothSpawn ( spawnpoint, team )
We give him an ak-47 (ID 30) with 10000 ammo.
 
giveWeapon ( source, 30, 10000 )
end
Main functions
 
function checkHillArea ()
Here we came to the main function, which is being called every 500 ms.
We create a table which stores all the players who are at the area to be captured.
 
     local hillPlayers = getElementsWithinColShape ( hillArea, "player" )
Check every player in the table with isPlayerDead() and if he is dead remove him from the table with table.remove(), so he does not get points being dead.
 
     for k,v in hillPlayers do
          if ( isPlayerDead ( v ) ) then
               table.remove(hillPlayers,k)
          end
     end
After we removed all the dead players we check how many items are left in the table
 
     if table.getn ( hillPlayers ) ~= 0 then
If it is not 0 we set the area's color on the radar to red and make it flash, like when you capture areas in Single Player
 
          setRadarAreaFlashing ( hillRadar, true )
          setRadarAreaColor ( hillRadar, 255, 0, 0, 175 )
And for every player in the table we have to increase their points and update their text displays. So we get their current points and text displays with getElementData(), add 1 point and update the text items with textItemSetText()
 
          for k,v in hillPlayers do
               local currentPoints = getElementData ( v, "points" )
               local newPoints = currentPoints + 1setElementData ( v, "points",
 newPoints )
               textItemSetText ( getElementData(v,"textItemPoints"), 
"Score: "..newPoints )
          end
Else, if there are no players left in the table we set the area color to green and make it not falsh on the radar.
 
     else
          setRadarAreaFlashing ( hillRadar, false )
          setRadarAreaColor ( hillRadar, 0, 255, 0, 175 )
     end
Now we need to print the leader.
 
     local leaderText = ""
     local leaders = 1
     for k,v in getElementsByType ( "player" ) do
If there is no leader yet, the first player we get will be it.
 
          if leaderPlayer == false then leaderPlayer = v end
Then if the current player checked is not the leader we get his and leader's points
 
          local leaderPoints = getElementData ( leaderPlayer, "points" ) 
          playerPoints = getElementData ( v, "points" )
If the player has more points than the leader, we update the leader
 
               if playerPoints > leaderPoints then
                    leaders = 1
                    leaderPlayer = v
                    leaderText = getClientName ( v )
If they have the same amount of points, we have two leaders.
 
               elseif playerPoints == leaderPoints then
                    leaders = leaders + 1
                    leaderText = leaderText.."/"..getClientName(v)
               end
          end
     end
And if there are less than 3 leaders, and the leader himself exists, we print him
 
     if leaders > 3 or leaders == getPlayerCount () or leaderPlayer == false then
          textItemSetText ( textItemLeaderScore, "Leader: None" )
     else
          textItemSetText ( textItemLeaderScore, "Leader: "..leaderText.."
 - "..getElementData(leaderPlayer,"points") )
     end
end
When we end our round
 
function kothEnd ( )
We kill the main timer, so we dont get points any more
 
killTimer ( kothTimer )
Get the leaders the same way as before and display them with a new text display
 
     local leaderText = ""
     local leaders = 1
     for k,v in getElementsByType ( "player" ) do
          if leaderPlayer == false then leaderPlayer = v end
 
          local leaderPoints = getElementData ( leaderPlayer, "points" ) 
          playerPoints = getElementData ( v, "points" )
          if v ~= leaderPlayer then
               if playerPoints > leaderPoints then
                    leaders = 1
                    leaderPlayer = v
                    leaderText = getClientName ( v )
               elseif playerPoints == leaderPoints then
                    leaders = leaders + 1
                    leaderText = leaderText.."/"..getClientName(v)
               end
          else
               leaderText = getClientName (leaderPlayer )
          end
     end
     local textDisplayWinner = textCreateDisplay ()
     local textItemif leaders > 3 or leaders == getPlayerCount ()
or leaderPlayer == false then
          textItem = textCreateTextItem ( "The time is out!\nWinner: None
\nNewRound!", 0.5, 0.5, 2, 255, 0, 0, 255, 255 )
     else
          textItem = textCreateTextItem ( "The time is out!\nWinner: 
"..leaderText.." with "..getElementData ( leaderPlayer, "points" 
).."points!\n\nNewRound!", 0.5, 0.5, 2, 255, 0, 0, 255, 255 )
     end
     textDisplayAddText ( textDisplay, textItem )
     for k,v in getElementsByType ( "player" ) do
          textDisplayAddObserver ( textDisplayWinner, v )
          setElementData ( v, "points", 0 )
          textItemSetText ( getElementData(v,"textItemPoints"), "Score: 0" )
     end
And at last restart the resource
 
     restartResource ( getThisResource() )
end
Increased weapon damage
 
addEventHandler ( "onPlayerDamage", getRootElement(), "kothDamage" )
function kothDamage ( attacker, weapon, bodypart, loss )
If we were damaged by a player we set the new damage which is 125% of the previous one and check how much health do we have left.
 
          local damage = loss * 1.25
          local hpLeft = getPlayerHealth ( source ) - damage
If more than 0, then we are still alive, so we check the body part we have been hit in. And if it is the head we kill the player, if not change his hp with increased damage.
 
          if ( hpLeft > 0 ) then
               if ( bodypart == 9 ) then
                    killPlayer ( source, attacker, weapon, bodypart )
               else
                    setPlayerHealth ( source, hpLeft )
               end
Else if the player's health result is 0 or less, we just kill him.
 
          else
               killPlayer ( source, attacker, weapon, bodypart )
          end
     end
end
Messages
When a player enters/leaves the zone, we should output it
 
addEventHandler ( "onColShapeHit", -- getRootElement(), "kothHillEnter" )
function kothHillEnter ( player, dim )
     if source == hillArea then
          outputMessage ( getClientName(player).." entered the zone!",
255, 255, 109, 255 )
     end
end
 
addEventHandler ( "onColShapeLeave", -- getRootElement(), "kothHillExit" )
function kothHillExit ( player, dim )
     if source == hillArea then
          if isPlayerDead ( player ) ~= true then
               outputMessage ( getClientName(player).." left the zone!",
255, 255, 109, 255 )
          end
     end
end
And at last we output the death messages.
 
addEventHandler ( "onPlayerWasted", getRootElement(),
"KillMessages_onPlayerWasted" )
function KillMessages_onPlayerWasted ( totalammo, killer, killerweapon, bodypart )
Set up the nick of the killed player, message colors and alpha
 
     local killed_nick = getClientName ( source )
     local r,g,b = getPlayerNametagColor( source )
     local a = 120
If the player was in the koth zone, we set the Alpha to some bigger value, so we see it a bit better.
 
     if ( isElementWithinColShape ( source, hillArea ) ) then
          r = 255
          g = 255
          b = 109
          a = 255
     end
Else, we just output the messages a way similar to the one in the tutorial 5b.
 
     if ( killer ) then
          if (source == killer) then
               killed_nick = "himself"
          end
          local killmessage = getClientName(killer).." killed "..killed_nick
          local killerweapon_name = getWeaponNameFromID ( killerweapon )
          if ( killerweapon_name ) then
               outputMessage( killmessage.." ("
..killerweapon_name..")",  r, g, b, a )
          else
               outputMessage( killmessage, r, g, b, a )
          end
     else
          outputMessage( killed_nick.." died", r, g, b, a )
     end
end
 
------OUTPUT MESSAGE CODE-----
addEventHandler ( "onResourceStart", getRootElement(), "createTextOnLoad" )
function createTextOnLoad ( name )
     local outputMessageTextDisplay = textCreateDisplay ()
     local distance = 0.027
     local start = 0.25
     local size = 1.2
          outputMessageTextItem1 = textCreateTextItem ( "", 0.8, start + 
distance, 1, 255, 255, 255, 255, size )
          outputMessageTextItem2 = textCreateTextItem ( "", 0.8, start + 
(distance * 2 ), 1, 255, 255, 255, 255, size )
          outputMessageTextItem3 = textCreateTextItem ( "", 0.8, start + 
(distance * 3 ), 
1, 255, 255, 255, 255, size )
          outputMessageTextItem4 = textCreateTextItem ( "", 0.8, start + 
(distance * 4 ), 1, 255, 255, 255, 255, size )
          outputMessageTextItem5 = textCreateTextItem ( "", 0.8, start + 
(distance * 5 ), 1, 255, 255, 255, 255, size )
          outputMessageTextItem6 = textCreateTextItem ( "", 0.8, start + 
(distance * 6 ), 1, 255, 255, 255, 255, size )
     textDisplayAddText ( outputMessageTextDisplay, outputMessageTextItem1 )
     textDisplayAddText ( outputMessageTextDisplay, outputMessageTextItem2 )
     textDisplayAddText ( outputMessageTextDisplay, outputMessageTextItem3 )
     textDisplayAddText ( outputMessageTextDisplay, outputMessageTextItem4 )
     textDisplayAddText ( outputMessageTextDisplay, outputMessageTextItem5 )
     textDisplayAddText ( outputMessageTextDisplay, outputMessageTextItem6 )
     local players = getElementsByType ( "player" )
     for k,v in players do
          textDisplayAddObserver ( outputMessageTextDisplay, v )
     end
end
 
addEventHandler ( "onPlayerJoin", getRootElement(), "showTextPlayerJoin" )
function showTextPlayerJoin ()
     textDisplayAddObserver ( outputMessageTextDisplay, source )
end
 
function outputMessage ( text, r, g, b, a )
     local text2 = textItemGetText ( outputMessageTextItem2 )
     local r2,g2,b2,a2 = textItemGetColor ( outputMessageTextItem2 )
     local text3 = textItemGetText ( outputMessageTextItem3 )
     local r3,g3,b3,a3 = textItemGetColor ( outputMessageTextItem3 )
     local text4 = textItemGetText ( outputMessageTextItem4 )
     local r4,g4,b4,a4 = textItemGetColor ( outputMessageTextItem4 )
     local text5 = textItemGetText ( outputMessageTextItem5 )
     local r5,g5,b5,a5 = textItemGetColor ( outputMessageTextItem5 )
     local text6 = textItemGetText ( outputMessageTextItem6 )
     local r6,g6,b6,a6 = textItemGetColor ( outputMessageTextItem6 )
     textItemSetText ( outputMessageTextItem5, text6 )
     textItemSetColor ( outputMessageTextItem5, r6, g6, b6, a6 )
     textItemSetText ( outputMessageTextItem4, text5 )
     textItemSetColor ( outputMessageTextItem4, r5, g5, b5, a5 )
     textItemSetText ( outputMessageTextItem3, text4 )
     textItemSetColor ( outputMessageTextItem3, r4, g4, b4, a4 )
     textItemSetText ( outputMessageTextItem2, text3 )
     textItemSetColor ( outputMessageTextItem2, r3, g3, b3, a3 )
     textItemSetText ( outputMessageTextItem1, text2 )
     textItemSetColor ( outputMessageTextItem1, r2, g2, b2, a2 )
     ---
     textItemSetText ( outputMessageTextItem6, text )
     textItemSetColor ( outputMessageTextItem6, r, g, b, a )
     --
end