OFPEC Forum
Editors Depot - Mission Editing and Scripting => OFP - Editing/Scripting Multiplayer => Topic started by: trinec on 15 Sep 2005, 20:30:28
-
I have read the tutorial on creating a deathmatch but im kinda stuck on the scoring when it comes to a team deathmatch so that when each player makes a kill it scores for the team east vs west. Also I need a way to show which individual person got the most points during the round as well as the whole teams score.
Thanks
Trinec
-
you will need to research using killed event handlers and how to publicvariable
basically you add a killed eventhandler to each unit.
When a unit is killed, the event handler will return 2 values
Who was killed and by who
You can then check the side of the killer and add a score to their side
you could also add an individual score to the name of the killer
and then during your closing outro, you can display this in titletext messages or a hint message
Probably hint message due to the amount of units you would be displaying info for
something like the following
MISSION EDITOR
for the argument of this example, create 3 west and 3 east units
name then W1,W2,W3,E1,E2 and E3
INIT.sqs
;; following variables are for side scoring
tx_Wkills = 0
tx_Ekills = 0
;; following variables are for individual unit scoring
tx_W1score
tx_W2score
tx_W3score
tx_E1score
tx_E2score
tx_E3score
;; following is a killed eventhandler, this runs the playerkilled.sqs when the unit is killed (much more efficient than a series of triggers
tx_kill = player addEventHandler ["killed", {_this exec "playerkilled.sqs"}]
Playerkilled.sqs
_victim = _this select 0
_killer = _this select 1
_side = side _killer
player removeEventhandler ["Killed",tx_kill]
if(side _victim == _side)then{hint "teamkill occurred";exit}
goto (format ["%1",_side])
#EAST
if (name _killer == name E1)then {tx_E1score = tx_E1score + 1;tx_Ekills = tx_Ekills + 1; {Publicvariable _x}foreach ["tx_E1score","tx_Ekills"]}
if (name _killer == name E2)then {tx_E2score = tx_E2score + 1;tx_Ekills = tx_Ekills + 1; {Publicvariable _x}foreach ["tx_E2score","tx_Ekills"]}
if (name _killer == name E3)then {tx_E3score = tx_E3score + 1;tx_Ekills = tx_Ekills + 1; {Publicvariable _x}foreach ["tx_E3score","tx_Ekills"]}
goto "END"
#WEST
if (name _killer == name W1)then {tx_W1score = tx_W1score + 1;tx_Wkills = tx_Wkills + 1; {Publicvariable _x}foreach ["tx_W1score","tx_Wkills"]}
if (name _killer == name W2)then {tx_W2score = tx_W2score + 1;tx_Wkills = tx_Wkills + 1; {Publicvariable _x}foreach ["tx_W2score","tx_Wkills"]}
if (name _killer == name W3)then {tx_W3score = tx_W3score + 1;tx_Wkills = tx_Wkills + 1; {Publicvariable _x}foreach ["tx_W3score","tx_Wkills"]}
goto "END"
#END
;;; if respawn then add the following
@alive player
tx_kill = player addEventHandler ["killed", {_this exec "playerkilled.sqs"}]
exit
your outro script would then contain the following code
_message = ""
if(tx_Wkills > tx_Ekills}then{_message = "WEST WINS"}else{_message = "EAST WINS"}
if(tx_Wkills == tx_Ekills)then{_message = "Its A Draw"}
hint formaT [ "___ FINAL OUTCOME ___\n\n%1",_message]
~10
;; following are for the individual scoring screenprint
_w1 = format ["\n%1 had %2 kills",name W1, tx_W1score]
_w2 = format ["\n%1 had %2 kills",name W2, tx_W2score]
_w3 = format ["\n%1 had %2 kills",name W3, tx_W3score]
_E1 = format ["\n%1 had %2 kills",name E1, tx_E1score]
_E2 = format ["\n%1 had %2 kills",name E2, tx_E2score]
_E3 = format ["\n%1 had %2 kills",name E3, tx_E3score]
hint formaT [ "___ INDIVIDUAL SCORES ___\n%1%2%3%4%5%6",_w1,_w2,_w3,_E1,_E2,_E3]
the above system will add a point to the side of the _killer for each death, providing it isnt a teamkill and then add a score to the killer unit's personal score
NB>> I think the only way to maintain a check on who the _killer is for a respawning unit is to refer to it by name _unit, this is the reason for the lines
if(name_killer == name W1)then{....... etc
The above system can be made much more efficient and requiring much less lines of code by using the format command and nested arrays, however, i tried to keep it very simple to allow you to follow its logic without ctreating something which you would find unreadable and therefore not be able to adapt it more to your requirements
No doubt somebody will still do that and confuse you more, just watch for the additional posts :)
-
Im trying the scripts that you gave me which i really appreciate ive come across a problem when i get killed. It was giving me this error removeeventhandler type number expected array from this line Player removeEventhandler tx_kill does it need to be changed to this player removeEventhandler ["tx_kill",0]. Which I tried and it still gives an error on this line _side = _side _killer error unknown operator _killer ive only tested this with me getting killed as the player and ai doing the killing so not sure if thats where the problem is or not
trinec
-
oops sorry two stupid syntax
player removeEventhandler tx_kill
should be
player removeEventhandler ["Killed",tx_kill]
and
_side = _side _killer
should be
_side = side _killer
-
Well that fixed those errors but now i have another one
goto _side error goto type side expected String
thanks
trinec
-
sorry another silly syntax.....replace the line
goto _side
with
goto (format ["%1",_side])
-
looks like the scripts are working is their a way to have a music file play for the team that wins I already have the music files setup in the description.ext. I am trying to get it to play a certain music file when west side wins it plays a music file and when the east side wins it plays a different music file. I guess maybe it should call a script when either side wins so that it has the camera spin around the team that wins and plays a music file.
-
musicname needs to be pre defined in the description.ext, as you know.
Lets name this musuc classes as
Wwins
Ewins
Draw
have your end/outro script run the following code
OUTRO
_Winner = 0
;;;_winner = 1 (for a west win)...=2 (for an east win)..=0 (for a draw)
_message = ""
if(tx_Wkills > tx_Ekills}then{_message = "WEST WINS";_winner = 1}else{_message = "EAST WINS";_winner = 2}
if(tx_Wkills == tx_Ekills)then{_message = "Its A Draw";_winner = 0}
hint formaT [ "___ FINAL OUTCOME ___\n\n%1",_message]
if(_winner==0)then{playmusic "Draw"}else{if(_winner==1)then{playmusic "WWins"}}else{if(_winner==2)then{playmusic "EWins"}}
~10
;; following are for the individual scoring screenprint
_w1 = format ["\n%1 had %2 kills",name W1, tx_W1score]
_w2 = format ["\n%1 had %2 kills",name W2, tx_W2score]
_w3 = format ["\n%1 had %2 kills",name W3, tx_W3score]
_E1 = format ["\n%1 had %2 kills",name E1, tx_E1score]
_E2 = format ["\n%1 had %2 kills",name E2, tx_E2score]
_E3 = format ["\n%1 had %2 kills",name E3, tx_E3score]
hint formaT [ "___ INDIVIDUAL SCORES ___\n%1%2%3%4%5%6",_w1,_w2,_w3,_E1,_E2,_E3]
-
Thanks alot Terox you have been a great help do you know if I can mix the outro with camera scripts? For example the west wins the camera spins around the west flag and plays the WWins music. can the camera stuff be in the same script like under #WWins for west etc. or do i need to call another script I prob can do the camera stuff but im just not sure on how to call it.
One other thing I just thought of is it seems these scripts would work with respawning units but would that work with the outro script because it would never get called if the game never ended I guess the tdm was setup to only last so long then that would fix that part but to call the Outro when the time limit was over with Im not sure on..
ok ive tested the scoring side and I get this when it displays the score scaler bool array string 0xfcfffffff kills
also on this line
if(_winner==0)then{playmusic "Draw"}else{if(_winner==1)then{playmusic "WWins"}}else{if(_winner==2)then{playmusic "EWins"}}
it gives me an error message from else but i cant read the whole message
-
Simple Answer = YES
MP outro's arent the same thing as an SP outro, all they are is a scripted cutscene
Basically you change the camera target, start and end positions
lets make it very simple, then you can expand on it as much as you want
You could do
?(_winner == 0):goto "DRAW"
?(_winner == 1):goto "WWins"
?(_winner == 2):goto "EWins"
#DRAW
;; do your camera stuff & screenprint your messages etc
exit
#WWins
;; do your camera stuff & screenprint your messages etc
exit
#EWins
;; do your camera stuff & screenprint your messages etc
exit
or if you dont want to repeat your code and goto "labels"
You can define the camera positions like this
?(_winner == 0):_camstart = (getpos objectnameA);_target = objectnameB;_camend = (getpos objectnameC)
?(_winner == 1):_camstart = (getpos objectnameD);_target = objectnameE;_camend = (getpos objectnameF)
?(_winner == 2):_camstart = (getpos objectnameG);_target = objectnameH;_camend = (getpos objectnameI)
and then run your camera cutscene like this
_camera = "camera" camCreate _camstart
_camera camSetTarget _target
_camera camSetRelPos [1,1,1.25]
_camera camCommit 0
@camCommitted _camera
etc etc etc
-
Didnt know if you had seen the last part of my message i had added it latter so maybe not
ok ive tested the scoring side and I get this when it displays the score scaler bool array string 0xfcfffffff kills
also on this line
if(_winner==0)then{playmusic "Draw"}else{if(_winner==1)then{playmusic "WWins"}}else{if(_winner==2)then{playmusic "EWins"}}
it gives me an error message from else but i cant read the whole message
next part below if _Winner = 0 at the start then doesnt that automaticly set it to a draw
_Winner = 0
;;;_winner = 1 (for a west win)...=2 (for an east win)..=0 (for a draw)
_message = ""
if(tx_Wkills > tx_Ekills}then{_message = "WEST WINS";_winner = 1}else{_message = "EAST WINS";_winner = 2}
if(tx_Wkills == tx_Ekills)then{_message = "Its A Draw";_winner = 0}
hint formaT [ "___ FINAL OUTCOME ___\n\n%1",_message]
if(_winner==0)then{playmusic "Draw"}else{if(_winner==1)then{playmusic "WWins"}}else{if(_winner==2)then{playmusic "EWins"}}
-
Take this code, then delete all the spaces so it fits on one line:
if(_winner==0)then{
playmusic "Draw";
}else{
if(_winner==1)then{
playmusic "WWins";
}else{
if(_winner==2)then{
playmusic "EWins";
};
};
};The indentation is just there so that anyone can easily check if the code is correct - in fact I recommend that anyone writing function-type code, which they intend to fit on one line in a sqs script file, writes it like this first and then puts it onto one line.
OFP script is stupid in that it doesnt have any such thing as 'else if', only 'if' and 'else', and OFP reads Terox's code as
"if () then {} else {} else{}"
, which doesnt make sense. If you want to simulate "else if's" then you have to nest the if statement inside the else one.
-
fraqori thanks for the help that fixed the music not playing my biggest problem is the individual scoring when it shows the hint box when the time runs out for the game and list the individual scores it shows the player names but states
trinec had scalar bool array string 0xfcfffffff kills
which is from this line
_w1 = format ["\n%1 had %2 kills",name W1, tx_W1score]
this is from the playerkilled script im not sure if this is right or not?
#WEST
if (name _killer == name W1)then {tx_W1score = tx_W1score + 1;tx_Wkills = tx_Wkills + 1; {Publicvariable _x}foreach ["tx_W1score","tx_Wkills"]}
if (name _killer == name W2)then {tx_W2score = tx_W2score + 1;tx_Wkills = tx_Wkills + 1; {Publicvariable _x}foreach ["tx_W2score","tx_Wkills"]}
goto "END"
-
First thing, make sure you have declared all your score variables as
variablename = 0 in
the init.sqs
next thing, is a quick tutorial on how to debug a script.
All a script does is
1) Have inputs
2) process the inputs
3) Create outputs
Very basically this means
1) Variables in
2) Do something with them
3) Variable output
So to figure out why something isnt working as expected, we have some great tools
Hint or Titletext
Side/group/vehiclechat
and
Format
Together these are simply used to display a text message on screen.
The text message can either be a simple string
eg
hint "DEBUG: Killed event script, at Label LOOP"
Which
you would place just after the #LOOP line
This tells you that your script, when ran got at least this far
If you wanted to monitor a lot of labels in a fast looping script, you could use
Player groupchat "DEBUG: At label 1"
Player sidechat "DEBUG: At label 2"
Player vehiclechat "DEBUG: At label 3"
this then allows you to scroll up the messages in the chat window at leisure and each label can clearly be distinguished by the different coloured chat text
FORMAT
Probably the most powerful command you will need to know for debugging purposes
Lets take your killed event script.
In particular, the tx_W1score
It should be declared in the init.sqs as having a value of 0
so to check, we place the the following line at the end of the Init.sqs
hint format ["Variable tx_W1score has value\n %1",tx_W1score]
if the Output is 0, you know the problem doesnt lie here
so you go to the next script that uses it and once again you place the same line in the script and wait to see the output
another approach, is taking a "Copy" of the value of "tx_W1score" before and after it is processed
eg
in a script that states
tx_W1score = tx_W1score + 1
you would do the following
_a = tx_W1score
tx_W1score = tx_W1score + 1
_b = tx_W1score
hint format ["Variable _a = %1\n\n Variable _b = %2",_a,_b]
do the same for the variables
name _killer etc etc etc
Using the above methods will then allow you to define where your problem lies and exactly what the problem is
Maybe a tutorial should be submitted to the editors depot, called "Debugging Tutorial"
Try using the above debugging system, then if you are still unable to resolve the problem, get back to us
-
Sorry Terox I didnt realize you gave me a broken init.sqs were some of the variables were not defined which is from your first post so now it works thanks for the debug info.
Init.sqs
;; following variables are for side scoring
tx_Wkills = 0
tx_Ekills = 0
;; following variables are for individual unit scoring
tx_W1score
tx_W2score
tx_W3score
tx_E1score
tx_E2score
tx_E3score
;; following is a killed eventhandler, this runs the playerkilled.sqs when the unit is killed (much more efficient than a series of triggers
tx_kill = player addEventHandler ["killed", {_this exec "playerkilled.sqs"}]
trinec
-
Here is the final part of the scripts the camera part is just something i added which does not have to be used.
Init.sqs
; following variables are for side scoring
tx_Wkills = 0
tx_Ekills = 0
; following variables are for individual unit scoring
tx_W1score = 0
tx_W2score = 0
tx_E1score = 0
tx_E2score = 0
;sets timeend to 0
TimeEnd=0
; following is a killed eventhandler, this runs the playerkilled.sqs when the unit is killed (much more efficient than a series of triggers
tx_kill = player addEventHandler ["killed", {_this exec "playerkilled.sqs"}]
Outro.sqs
_Winner = 0
;;_winner=1(for west win)..=2(for east win)..=0 (for a draw)
_message = ""
if(tx_Wkills > tx_Ekills)then{_winner = 1}else{_winner = 2}
if(tx_Wkills == tx_Ekills)then{_winner = 0}
;;when a certain side wins it goes to that part of the script
?(_winner == 0): goto "DRAW"
?(_winner == 1): goto "WWins"
?(_winner == 2): goto "EWins"
;camera stuff for when the score is equal to the same or no score at all this can be changed
#DRAW
playmusic "Draw"
_cam = "camera" camcreate [0,0,0]
_cam cameraeffect ["internal", "back"]
_cam camsettarget esol
_cam camsetrelpos [-2,10,3]
_cam camcommit 0
;shows its a draw on the screen
titleText ["IT'S A DRAW!!","Plain"]
titlecut [" ","BLACK IN",2]
~4
_cam camsetrelpos [-2,-5,0.5]
_cam camcommit 10
@camcommitted _cam
~2
_cam camsettarget wsol
_cam camsetrelpos [-1,3,2]
@camcommitted _cam
~2
titlecut [" ","BLACK OUT",2]
~2
_cam cameraeffect ["terminate", "back"]
camdestroy _cam
titlecut [" ","BLACK IN",2]
;;this tells the teamdeath match to end
TrueEnd=true
exit
#WWins
;plays a music file when the west side wins
playmusic "WWins"
;start of the scoreing part
hint formaT [ "___ FINAL OUTCOME ___\n\n%1",_message]
_W1 = format ["\n%1 had %2 kills",name W1,tx_W1score]
_W2 = format ["\n%1 had %2 kills",name W2,tx_W2score]
_E1 = format ["\n%1 had %2 kills",name E1,tx_E1score]
_E2 = format ["\n%1 had %2 kills",name E2,tx_E2score]
hint formaT [ "___ INDIVIDUAL SCORES ___\n%1%2%3%4",_W1,_W2,_E1,_E2]
;displays the scoring part for 7 seconds
~7
;this is the camera stuff for when the west side wins this can be change but the scoring must be called first before the camera part.
_cam = "camera" camcreate [0,0,0]
_cam cameraeffect ["internal", "back"]
_cam camsettarget wf1
_cam camsetrelpos [-2,15,5]
_cam camcommit 0
@camcommitted _cam
;shows west wins on the screen
titletext ["WEST WINS!!","Plain"]
~6
titlecut [" ","BLACK IN",2]
~2
_cam cameraeffect ["terminate", "back"]
camdestroy _cam
~1
titlecut [" ","BLACK IN",2]
;this ends the team death match
TrueEnd=true
exit
#EWins
;plays music for the east side when they win
playmusic "EWins"
;start of the east scoring part
hint formaT [ "___ FINAL OUTCOME ___\n\n%1",_message]
_W1 = format ["\n%1 had %2 kills",name W1,tx_W1score]
_W2 = format ["\n%1 had %2 kills",name W2,tx_W2score]
_E1 = format ["\n%1 had %2 kills",name E1,tx_E1score]
_E2 = format ["\n%1 had %2 kills",name E2,tx_E2score]
hint formaT [ "___ INDIVIDUAL SCORES ___\n%1%2%3%4",_W1,_W2,_E1,_E2]
~7
;start of camera stuff for east this can be changed
_cam = "camera" camcreate [0,0,0]
_cam cameraeffect ["internal", "back"]
_cam camsettarget ef1
_cam camsetrelpos [-2,15,5]
_cam camcommit 0
~3
titletext ["EAST WINS!!","Plain"]
~6
titlecut [" ","BLACK IN",2]
~2
_cam cameraeffect ["terminate", "back"]
camdestroy _cam
~1
titlecut [" ","BLACK IN",2]
;ends the team deathmatch
TrueEnd=true
exit
playerkilled.sqs
_victim = _this select 0
_killer = _this select 1
_side = side _killer
player removeEventhandler ["killed",tx_kill]
if(side _victim == _side)then{hint "teamkill occurred";exit}
goto (format ["%1", _side])
#EAST
if (name _killer == name E1)then {tx_E1score = tx_E1score + 1;tx_Ekills = tx_Ekills + 1; {Publicvariable _x}foreach ["tx_E1score","tx_Ekills"]}
if (name _killer == name E2)then {tx_E2score = tx_E2score + 1;tx_Ekills = tx_Ekills + 1; {Publicvariable _x}foreach ["tx_E2score","tx_Ekills"]}
goto "END"
#WEST
if (name _killer == name W1)then {tx_W1score = tx_W1score + 1;tx_Wkills = tx_Wkills + 1; {Publicvariable _x}foreach ["tx_W1score","tx_Wkills"]}
if (name _killer == name W2)then {tx_W2score = tx_W2score + 1;tx_Wkills = tx_Wkills + 1; {Publicvariable _x}foreach ["tx_W2score","tx_Wkills"]}
goto "END"
#END
;;; if respawn then add the following
@alive player
tx_kill = player addEventHandler ["killed", {_this exec "playerkilled.sqs"}]
description.ext
;this is for the setting of the time and scoring limits at the start of the mission
titleParam1 = "Time:";
valuesParam1[] = {10000, 300, 600, 900, 1200, 1500, 1800, 2700, 3600, 7200};
defValueParam1 = 1800;
textsParam1[] = {"Unlimited", "5 min", "10 min", "15 min", "20 min", "25 min", "30 min", "45 min", "1 hour", "2 hours"};
titleParam2 = "Score to win:";
valuesParam2[] = {10000, 5, 7, 10, 15, 20, 25, 30};
defValueParam2 = 5;
textsParam2[] = {"Unlimited", 5, 7, 10, 15, 20, 25, 30};
You also need to create some triggers for your map
first one is called Scorelimit which when the score that is set at the start of the mission is reached then this is called and ends the tdm
In the condition filed you put
(param1<10000 and ((time >= param1) or (TimeEnd >= param1))) or (param2<10000 and ((tx_W1score >=param2) or (tx_W2score >=param2) or (tx_E1score >=param2) or (tx_E2score >=param2)))
the on activation you put
TimeEnd=time; publicVariable "TimeEnd";player exec "Outro.sqs"
The next trigger is named End
Type is End1
in the condition field you put TrueEnd and in the on activation field you put ForceEnd
if anyone would like to add an update for every so many minutes you get updated on how much time you have left let me know and ill add it Just didnt want to put too much in here Thanks goes to Terox for the base scripts and for the debug info :), worked out the last part of the scoring triggers from reading the old ctf tutorial on the old sventh website
http://www.3dactionplanet.com/flashpoint/Tutorial2/Tutor2_Contents.html
and for fragori's help.
Trinec