Official Soldat Forums
Server Talk => Scripting Discussions and Help => Topic started by: DarkCrusade on March 30, 2010, 09:36:25 am
-
I just decided to learn scripting by myself since I have a lot of ideas for scripts that I´d like to code on my own. So I checked the existing threads and slowly get into it. But I have no idea what I need to do for this one:
(1)
I want to set the health of a player that scored for his team to 300. I began like
procedure OnFlagScore (ID, TeamFlag: byte )
begin
end;
But I am not sure how to go on. I know that the function that I need to use is "SetPlayerStat" but I guess I will need to save the ID of that player as an int before, but how?
(2)
I know Java and HTML. Soldat scripting is totally new to me. Is it Pascal? And what is right? One or two:
#1:
thenbegin
#2:
then begin
-
1 - The ID of the player is already given in that event as a byte. You can input a byte where an integer is expected, not the other way around though. Filling in ID for ID will (always) work.
Instead of setPlayerStat you can use getPlayerStat and DoDamage with negative value (if you're using old script core).
2 - Soldat scripting is based on pascal/delphi. Google "delphi something" usually works for me if I need to know something.
The begin-end syntax is used to identify code blocks. If...then reads a single line as statement by default, but instead you can use begin-end to make it execute multiple lines. A lot of commands in pascal expect single lines by default, so begin-end blocks are used for other things as well (for-loops, case statements, functions).
if..then single line:
if (i=0) then //set a condition, statement will follow
WriteLn('i is zero!');
//more code outside of if..then statement, thus will always be executed:
WriteLn('Hello World!');
if.. then multiple lines:
if (i=0) then begin //set condition, statement until end
//so all this code will only be executed if i is zero
WriteLn('i is zero!');
WriteLn('Hello World!');
end;
-
I am a little bit confused because of iDantes scripting tutorial (--- (http://forums.soldat.pl/index.php?topic=29911.0)). I copied his code (Part II) and tried running the server but I got this error message and I don´t know how to read and understand it ...
(http://www.fileupyours.com/files/276154/Error.png)
Also could you tell me whether my line comment is right?
function OnPlayerCommand(ID: Byte; Text: string): boolean; // When a player uses a command the function starts
// and checks whether the condition is true or not
var i: integer; // declaration of the variable i of the type integer
begin // start
if Text = '/asplode' then begin // condition for the function
for i := 1 to 32 do begin // check the player IDs?
if GetPlayerStat(i, 'active') then Command('/kill '+inttostr(i));
// If he´s active he gets killed (could you explain "inttostr(i)"?)
end;
end;
end;
-
IntToStr in Integer To String, because you execute a command and thats a string, but your i-variable is an integer.
-
Most answers for your questions can be found on soldat scripting tutorial: http://enesce.com/help/
Also, try reading some code of already done by someone else scripts to learn things.
-
I already do that, but still some questions come up. Is the line comment right?
-
The numbers in the error match (line+1:char), line+1 meaning that the first line in your script is line 2 in the compiler.
I don't see any problem with the syntax on line 5 or before that (comments seem ok), so I don't really understand why you get this message. You might want to re-check Includes.txt and maybe you could try different encoding for the files (utf-8 should always work i think).
-
-What are the alternatives for "onscriptcrash = shutdown"?
I am still working on the script. I just don´t get what´s the problem and I already checked different encoding types for the files and I didn´t see any difference. However, I think the problem doesn´t lie in Includes.txt since the script shouldn´t be loaded if Includes.txt has some failures, or am I wrong?
For those who are interested: Script attached.
-
Permutations:
shutdown
disable
recompile
-
Okay, I worked on the script that sets a players health to 300 after he scored for his team and the code is so simple that I am a bit embarrassed that I´m getting the error message that a ";" is expected in line 3 ...
procedure OnFlagScore (ID, TeamFlag: byte )
begin
SetPlayerStat(ID, 'health', GetPlayerStat(ID, 'health') = 300);
end;
-
procedure OnFlagScore (ID, TeamFlag: byte );
begin
SetPlayerStat(ID, 'health', GetPlayerStat(ID, 'health') = 300);
end;
Something I used to do too.
Haven't toyed around with scripting for ages, may be wrong, might as well try.
-
Max HP is 200.
-
You need to scale the damage done using thier desired max health. Ill post an example onplayerdamage tomarrow if you want.
-
Okay, so I can get their health stat, substract it from 300 and add this amount of health?
@Chutem: I knew I´d miss something that trivial.
-
If you want set not standart hp, you must create type/global variable, that will hold player health.
In on player damage you substracting damage from value, not player health, and killing player if virtual hp is less than 0.
In other way(as hacktank said) you must scale damage, something like this:
Damage := (Damage * ((100 * Hp) div MaxHp)) div 100; //may not works, written on fast
First way is better(IMO).
-
Permutations:
shutdown
disable
recompile
recompile doesn't work for me, never seen it recompiling.
-
Max HP is 200.
Yus, very Important, you can not go over these 200HP without fake health.
But you should leave this for now since it's an more advanced part.
You can not use the SetPlayerStat() function, it's not supported by the current script core.
If you wanna set the health to the maximum use that:
DoDamage(ID, -200); //Heals them up to 200HP, w/e health they had before, if they're alive
Note: Negative Damage heals players.
Permutations:
shutdown
disable
recompile
recompile doesn't work for me, never seen it recompiling.
Same here, it displays some message ingame that the script crashed and is recompiling, but it isn't.
-
if you're not going to use modified health anywhere else, it's useless to make a whole custom health system imo. Just give a vest
-
I have a question !
i use special bot by Gizd but how i put the weapon of the bot as fist
i've tried to put 255 but nothing ...
-
I have a question !
i use special bot by Gizd but how i put the weapon of the bot as fist
i've tried to put 255 but nothing ...
Yes, the title looks like you can ask your questions here about scripting but it's not like that actually.
edit: Or is it?
-
function OnPlayerDamage(Victim,Shooter: Byte;Damage: Integer) : integer;
begin
result := damage;
if (damage>0) AND (damage<3000) AND (shooter<>victim) then begin
result := damage * (150.0/desiredmaxhealth);
end;
end;
-
Hm, I tried compiling your script a day ago and got an error that I am not able to fix by myself.
(http://www.fileupyours.com/files/276154/Error2.png)
I messed a bit with it for some time but got no positive results.
function OnPlayerDamage(Victim,Shooter: Byte;Damage: Integer;) : Integer;
begin
result := damage;
if (damage>0) AND (damage<3000) AND (shooter<>victim) then begin
result := damage * (150.0/desiredmaxhealth);
end;
end;
// desiredmaxhealth,300 : Integer;
// desiredmaxhealth: Integer;
I tried declaring desiredmaxhealth as a variable and stuff the way I know it from Java and afterwards tried declaring it like the variables you declared in OnPlayerDamage(...); but that didn´t work either so now I really need help. I didn´t get the other scripts working, too, so ...
-
You only need ; to separate the arguments of a function, the last one is not needed.
In other words remove ; after Damage: Integer
-
Thanks JFK, that was one bug. But another one occured that I was able to find by the super-special bugfinding tactic that I use in Java (take out lines to see whether something changes).
function OnPlayerDamage(Victim,Shooter: Byte;Damage: Integer) : Integer;
begin
result := damage;
if (damage>0) AND (damage<3000) AND (shooter<>victim) then begin
result := damage * (150.0/desiredmaxhealth); // THIS LINE CAUSES THE ERROR
end;
end;
-
Did you specify the desiredmaxhealth before the first begin as a const?
Something like this:
function OnPlayerDamage(Victim,Shooter: Byte;Damage: Integer) : Integer;
const
desiredmaxhealth= *THIS BE EDITED TO VALUE YOU WANT*;
begin
result := damage;
if (damage>0) AND (damage<3000) AND (shooter<>victim) then begin
result := round(damage * (150.0/desiredmaxhealth));
end;
end;
-
Hell my script looked exactly like yours, croat, I just forgot I need to declare variables via "const" ... Thanks for reminding me.
EDIT:
procedure OnAdminMessage(IP, Msg: String);
begin
if (Msg='/say') then begin
procedure WriteLn(Output: String);
Output='/say #################';
end;
end;
This is my latest project. To make admin messages more visable I want the script to add a line of charakters that highlight the admin messages so that even totally focussed players will be seeing those messages that may be important for them.
The compilation fails: Admin Text -> [ERROR] (5:3): Identifier expected.
And I really don´t know what could have caused this problem that has occured before. I hope it´s no general problem ... I checked my settings already.
EDIT#2:
I am also working on a script that adds a bot as spectator who comments the happenings at the server. I´m getting the error, that a ´;´ is expected in (3:3).
// When the server starts for the first time a bot should be added as a spectator. He will comment the game/////////
procedure ActivateServer()
begin
Command ('/addbot5 Spectator');
end;
end;
// If a flag is stolen the spectator bot writes the comment below. He has ID #1, because he join OnServerStart /////
procedure OnFlagGrab(ID, TeamFlag: byte;GrabbedInBase: boolean)
begin
procedure BotChat(ID:Byte;Text:string)
begin
BotChat(1,'Players keeps sake! Flag has been taken!')
end;
end;
end;
I will hopefully be able to add more functions to this script as it is the most important one for me right now. It´s not so hard to add more but I want to keep it as simple as possible right now so I don´t need to look through a giant script that I need to understand again first.
-
procedure OnAdminMessage(IP, Msg: String);
begin
if Copy(Msg, 1, 4)='/say' then
WriteConsole(0, '#################', $FFFF00);
end;
var BotID: byte;
procedure ActivateServer();
var a: byte;
begin
a := NameToID('Spectator');
if a > 0 then KickPlayer(a);
botID := Command('/addbot5 Spectator');
end;
procedure OnFlagGrab(ID, TeamFlag: byte;GrabbedInBase: boolean);
begin
BotChat(BotID,'Players keeps sake! Flag has been taken!');
end;
Untested
-
First one: You uses Output=, pascal uses := to set values to variables.
Second one: You are forgetting your ;'s after procedure declerations, also BotChat is a built in function, yes? - you don't need to declare it. On a similar note, not sure if you can declare a procedure within a procedure in pascal, but calling the procedure BotChat (which you don't need to declare) will create an infinite loop until the script crashes.
Therefore just remove the red lines: (remember to fix what's left, though)
procedure OnFlagGrab(ID, TeamFlag: byte;GrabbedInBase: boolean)
begin
procedure BotChat(ID:Byte;Text:string)
begin
BotChat(1,'Players keeps sake! Flag has been taken!')
end;
end;
end;
Also need to watch your begin-end pairs, there is an extra end; in there, see if you can find it.
Oh and damn you tk you replied while i was previewing my BB code, but I think this will help so I'm leaving it, plus it took me more than a minute to write.
And one final note: DarkCrusade, your apostrophe's are annoying me, you may not have noticed, but spot the difference:
apostrophe'd word
apostrophe´d word 2
Yeah it's a minor niggle, but I have been noticing it for ages :|
-
Thanks for your advice!
!= means "is not". right? But how can I compare one variable to another and return a boolean? And which apostrophe´s shall I use? Do I get errors for using the wrong one?
-
no, in pascal it's <>
BooleanResult := Value1 = Value2;
if they are equal, the result will be true.
-
procedure ActivateServer();
begin
Command ('/addbot5 Spectator');
end;
procedure OnFlagReturn(ID, TeamFlag: byte);
begin
BotChat(1,'Flag returned!');
end;
procedure OnFlagDrop(ID, TeamFlag: byte);
begin
BotChat(1,'Flag got lost!');
end;
//procedure OnFlagGrab(ID, TeamFlag: byte;GrabbedInBase: boolean);
// if(GrabbedInBase := 1) begin
// BotChat(1,'Players keeps sake! Flag has been taken!');
// end;
//function OnPlayerCommand(ID: Byte; Text: string): boolean;
// if (Text:='/kill') OR (Text:= '/brutalkill') then begin
// BotChat(1,'Don´t you dare to suicide again!')
// Command('/kill ' + ID);
//procedure OnFlagScore(ID, TeamFlag: byte);
// begin
// BotChat(1,'One score, one point!');
// end;
As you can see I worked more on my script and the lines that aren´t cut out don´t return any errors except that they don´t work at my home hosted server. For OnFlagScore and OnFlagGrab it returns the error that it expects a "begin" somewhere ...
-
OnFlagReturn and OnFlagDrop aren't supported by the current server version, use v265.
procedure OnFlagGrab(ID, TeamFlag: byte; GrabbedInBase: boolean);
begin
if GrabbedInBase then
BotChat(1, 'Players keeps sake! Flag has been taken!');
end;
Note: You always need an begin after you declare an procedure/function, and don't forget to add an end;
Some examples on boolean: (May helps)
procedure BooleanTest;
var Bool: boolean;
begin
Bool := true; // Set to false an it'll output 2 times "Bool is false"
if Bool then WriteLn('Bool is true!');
if not Bool then WriteLn('Bool is false!');
if Bool = false then WriteLn('Bool is false!');
if Bool = true then WriteLn('Bool is true!');
end;
But you should go with the first two methods, most don't like the last two since it's really useless text.
I'm not sure about if = 1 or = 0 works too, but I think it does. And like the two examples above it's unnecessary text.
-
WriteLn('Bool is ' + iif(Bool,'true','false') + '!');
\o/
-
Gizd Gizd Gizd!! I tried to explain him the ways he can check if a bool is true/false.
Anyway thats too one xD
-
You are messing up your operators.
In this line
if(GrabbedInBase := 1) begin
You are using the assignment operator (:=) instead of the equality operator (=)
Basically how I think of it, your line reads as 'if set GrabbedInBase to 1 is true then begin', which doesn' make much sense in english, so it _doesn't make much sense in code_ (not sure if it is like this in pascal, but assigning to a variable can return true/false whether it was successful/not).
The correct line would be
if(GrabbedInBase = 1) begin
Which would read as 'if GrabbednBase is equal to 1 then begin', which makes much more sense.
So if, as tk said, you used <>, it would read 'if GrabbedInBase is not equal to 1 then begin'
Btw, your apostrophes are not related to pascal, they just make your sentences with them look wierd.
-
Maybe I am rushing, maybe I´m not, but I try to create a bigger script for the knife server I have in mind. First of all I want to create a script that will tell players that join what kind of server they did join. For this I used ...
procedure OnJoinGame(ID,Team:Byte);
then begin
WriteConsole(ID,'Text');
WriteConsole(ID,'Text');
WriteConsole(ID,'Text');
end;
But it returns the error, that in (4:3) it expects 'begin'. I tried seperating the lines with 'begin' and 'end;' but then I got the same error that I got with just 'begin' at the start, 'invalid number of parameters'.
-
Remove the 'then', it is confusing the compiler.
Are you trying to use the procedure as some kind of if statement?
-
No, I just want that every joining player gets this message. If I remove ´then´ I get the error that there is an invalid number of parameters like I stated already :S
-
http://enesce.com/help/index.html?Functions/WriteConsole.html
procedure WriteConsole(ID: Byte; Text: string; Colour: Longint)
-
So I tried
procedure OnJoinGame(ID,Team:byte);
then begin
WriteConsole(ID,'Hello, this server is scripted.'; $FFFFFFFF);
WriteConsole(ID,'You can choose out of 4 classes.'; $FFFFFFFF);
WriteConsole(ID,'For further information type !help.'; $FFFFFFFF);
end;
procedure OnJoinGame(ID,Team:byte);
begin
procedure WriteConsole(ID:Byte;Text:String;Colour:Longint);
then begin
WriteConsole(ID,'Hello, this server is scripted.'; $FFFFFFFF);
WriteConsole(ID,'You can choose out of 4 classes.'; $FFFFFFFF);
WriteConsole(ID,'For further information type !help.'; $FFFFFFFF);
end;
end;
And right now I can´t check the logs. It saves them without any text ...
-
COMMA IN BETWEEN PARAMETERS, NOT A SEMICOLON
-
procedure OnJoinGame(ID,Team:byte);
begin
procedure WriteConsole(ID:Byte;Text:String;Colour:Longint);
then begin
WriteConsole(ID,'Hello, this server is scripted.'; $FFFFFFFF);
WriteConsole(ID,'You can choose out of 4 classes.'; $FFFFFFFF);
WriteConsole(ID,'For further information type !help.'; $FFFFFFFF);
end;
end;
What's that "then begin" for?
-
My logs work again. Right now ...
procedure OnJoinGame(ID,Team:byte);
begin
procedure WriteConsole(ID:Byte;Text:String;Colour:Longint);
begin
WriteConsole(ID,'Hello, this server is scripted.', $FFFFFFFF);
WriteConsole(ID,'You can choose out of 4 classes.', $FFFFFFFF);
WriteConsole(ID,'For further information type !help.', $FFFFFFFF);
end;
end;
I ... don´t quit understand what my failure is ... maybe you could simply correct it and I will see what I´m doing wrong?
-
Why you have function declaration in another function?
-
procedure OnJoinGame(ID,Team:byte);
begin
procedure WriteConsole(ID:Byte;Text:String;Colour:Longint);
begin
WriteConsole(ID,'Hello, this server is scripted.', $FFFFFFFF);
WriteConsole(ID,'You can choose out of 4 classes.', $FFFFFFFF);
WriteConsole(ID,'For further information type !help.', $FFFFFFFF);
end;
end;
You do not have to declare the WriteConsole() procedure since its build-in.
procedure OnJoinGame(ID, Team: byte);
begin
WriteConsole(ID, 'Hello, this server is scripted.', $FFFFFFFF);
WriteConsole(ID, 'You can choose out of 4 classes.', $FFFFFFFF);
WriteConsole(ID, 'For further information type !help.', $FFFFFFFF);
end;
-
My script works now, but that´s the one I had before (not posted) so I am confused now (that is why I tried everything, too ...), seems like it was caused by the same error that destroyed my logs but it is fine now :)
Since the script works now I worked on it further and added the commands !help and the commands !classes, !credits and !rules but I have no idea yet how I can implement the different classes ...
Can I use more than one script or can I use only one big mainscript? It would be hellalot easier ...
I just compiled my script again and tried it online. Nothing happens ... I tried the different commands but really nothing happened ... /info told me scripts are compiled and that scripting is enabled. Since I don´t want to copy 75 lines I just attached it.
-
[EDIT]
Here is your problem, you used WriteLn (http://devs.soldat.pl/wiki/index.php?title=Writeln) insteaf of WriteConsole (http://devs.soldat.pl/wiki/index.php?title=WriteConsole) which is displaying text to a player ingame. (WriteLn displays it to admins, in ARSSE for example)
You could split it off in different scripts, but I'd highly recommend having one big script for a mod.
Even though that class thing will be a harder part.
You should now get used to type:
// Declare the type
type
TPlayer = Record
Task: byte; // I used task instead of Class because Class is a reserved word :/
end;
// Now create an array, one index slot for each player
var
Player: Array [1..32] of TPlayer;
// Looks like that when you use it:
procedure SetTask(ID, Task: byte);
begin
Player[ID].Task := Task;
end;
When you understand that you should think about the variables the players will need in your script and add them to that. If your going to make this Knife Only Mod you mentoined in Adverts you should add for example an timer how long it needs till he gets a new knife.
-
So I got some more time and got the first part working.
procedure OnJoinGame(ID,Team:byte);
begin
SayToPlayer(ID,' Text');
SayToPlayer(ID,'Text');
end;
But this part is returning an error I cannot fix with my current knowledge: (Invalid number of parameters again)
procedure OnPlayerSpeak(ID:Byte;Text:String);
begin
if(Text='!help')
then begin
WriteConsole('/say ', $FFFFFFF);
WriteConsole('/say ', $FFFFFFF);
end;
-
only need to do
procedure OnJoinGame(ID,Team:byte);
begin
WriteConsole(ID,'Welcome to my server',$EE81FAA1);
WriteConsole(ID,'Welcome text here !!!!!!,$EE81FAA1);
end;
ID, will say only to the guys who have joined the game the thing !
-
WriteConsole(ID: byte; Text: string; Color: longint);
That are the parameters, I think I don't need to explain which one is for what ;)
You need to set each of it to a value otherwise it will throw errors.
However if you want to use /say you need to use Command (http://devs.soldat.pl/wiki/index.php?title=Command)
Command('/say Hello World');
But I'd highly recommend using WriteConsole (http://devs.soldat.pl/wiki/index.php?title=WriteConsole) since you can make that text colored and there won't be a *SERVER* infront of your text.
For the joining palyers you should use that how you've done it already instead of using SayToPlayer;
procedure OnJoinGame(ID, Team: byte);
begin
WriteConsole(ID, 'Hello, this server is scripted.', $FFFFFFFF);
WriteConsole(ID, 'You can choose out of 4 classes.', $FFFFFFFF);
WriteConsole(ID, 'For further information type !help.', $FFFFFFFF);
end;
In your second code, you are missing and end; aswell the first parameter of WriteConsole, try fixing it yourself, look at the latest working examples to find out what went wrong.
-
And that
procedure OnPlayerSpeak(ID:Byte;Text:String);
begin
if(Text='!help')
then begin
WriteConsole(ID,'Hmmm sorry but...',$EE81FAA1);
WriteConsole(ID,'THERE IS NO HELP FOR THIS SERVER',$EE81FAA1);
end;
-
Damnit ...
10-04-05 21:09:48 [*] Compiling Knife Server -> KnifeServer.pas...
10-04-05 21:09:48 [*] Knife Server -> [Error] (33:10): Identifier expected
10-04-05 21:09:48 [*] Compilation Failed.
10-04-05 21:09:48 Shutting down server...
After I added ...
procedure OnPlayerSpeak(ID:Byte;Text:String);
begin
if(Text='!help')
then begin
WriteConsole(0,'/say ', $FFFFFFF);
WriteConsole(0,'/say ', $FFFFFFF);
WriteConsole(0,'/say ', $FFFFFFF);
WriteConsole(0,'/say ', $FFFFFFF);
WriteConsole(0,'/say ', $FFFFFFF);
WriteConsole(0,'/say ', $FFFFFFF);
end;
Am I really that dumb?
-
this is not good
procedure OnPlayerSpeak(ID:Byte;Text:String);
begin
if(Text='!help')
then begin
WriteConsole(0,'/say ', $FFFFFFF);
WriteConsole(0,'/say ', $FFFFFFF);
WriteConsole(0,'/say ', $FFFFFFF);
WriteConsole(0,'/say ', $FFFFFFF);
WriteConsole(0,'/say ', $FFFFFFF);
WriteConsole(0,'/say ', $FFFFFFF);
end;
You cannot tell command with WriteConsole
if you want to tell a command do
Command('/say TEXT HERE');
If you dont want the *SERVER* in front of your message do
WriteConsole(ID,'TEXT HERE',$EE81FAA1);
i hope that will help u :P
-
procedure OnPlayerSpeak(ID:Byte;Text:String);
begin
if(Text='!help')
then begin
WriteConsole(0,'/say ', $FFFFFFF);
WriteConsole(0,'/say ', $FFFFFFF);
WriteConsole(0,'/say ', $FFFFFFF);
WriteConsole(0,'/say ', $FFFFFFF);
WriteConsole(0,'/say ', $FFFFFFF);
WriteConsole(0,'/say ', $FFFFFFF);
end;
Use the power of logic:
- how many begins are there? - 2
- how many ends are there? - 1
-
Am I really that dumb?
im afraid so, if you cant count to TWO :/
-
Well, I already came to that conclusion. I just wasn´t sure :P Currently I am using ...
procedure OnPlayerSpeak(ID: Byte,Text: String);
if(Text=' ')
then
WriteConsole(ID,' ', $FFFFFFFF);
WriteConsole(ID,' ', $FFFFFFFF);
[...]
if(Text=' ')
then
WriteConsole(ID,' ', $FFFFFFFF);
WriteConsole(ID,' ', $FFFFFFFF);
[...]
end;
... so I have different conditions for the different WriteConsols, but if I type !help it will show all lines of my script ... again I tried different things but came to no conclusion.
Is there an offline scripting manual? I tried downloading EnEsCes Manuals first site and hoped it would work but it didn´t.
-
if you have 'then', without begin and end on a condition, it will work only on ONE line.
For example, let's say boolean 'execute' is set to false:
(...)
WriteConsole(0,'Hello Players1', $FFFFFFFF);
if execute then WriteConsole(0,'Hello Players2', $FFFFFFFF);
WriteConsole(0,'Hello Players3', $FFFFFFFF);
WriteConsole(0,'Hello Players4', $FFFFFFFF);
(...)
The script will display lines 1, 3, 4.
If you want it to display the lines 2 AND 3 depending on 'execute''s state:
(...)
WriteConsole(0,'Hello Players1', $FFFFFFFF);
if execute then begin
WriteConsole(0,'Hello Players2', $FFFFFFFF);
WriteConsole(0,'Hello Players3', $FFFFFFFF);
end
WriteConsole(0,'Hello Players4', $FFFFFFFF);
(...)
If 'execute' is false, lines 1 and 4 will be the output.
-
Just came back from Antwerpen and got some free time now to learn some more scripting stuff. I went further and tested my currently compiling script. Right now I use something like ...
procedure OnPlayerSpeak(ID:Byte;Text:String);
begin
if(Text='!help')
then
WriteConsole(0,' ###################Commands#####################', $FFFFFFF);
WriteConsole(0,'##!Classes: Will show you the different classes ##', $FFFFFFF);
WriteConsole(0,'## that you are able to choose. ##', $FFFFFFF);
WriteConsole(0,'##!Rules: Will show you the rules. ##', $FFFFFFF);
WriteConsole(0,'##!Credits: Will show you the credits. ##', $FFFFFFF);
WriteConsole(0,' ################################################', $FFFFFFF);
end;
But for some unknown reason it displays the text everytime I type anything. Be it a taunt or the command ... I don´t know what´s going wrong. It´s really bugging the shit out of me :S
-
wb DC.
procedure OnPlayerSpeak(ID:Byte;Text:String);
begin
if Text = '!help' then begin // You need a begin here so it displays all that text when a player types !help
WriteConsole(0,' ###################Commands#####################', $FFFFFFF);
WriteConsole(0,'##!Classes: Will show you the different classes ##', $FFFFFFF);
WriteConsole(0,'## that you are able to choose. ##', $FFFFFFF);
WriteConsole(0,'##!Rules: Will show you the rules. ##', $FFFFFFF);
WriteConsole(0,'##!Credits: Will show you the credits. ##', $FFFFFFF);
WriteConsole(0,' ################################################', $FFFFFFF);
end;
// If you want to add more "! commands" add one more
// if Text = '!cmd' then begin
// ... things shall be executed when someone typed !cmd
// end;
end;
Hope you get it ;)
-
Ah, my problem was that I have put the condition into brackets.
_________________________________________________ _____________
Now I wanted my script to display text when one condition is true. So I tried something like ...
if Text='!Help' OR Text='!help' then begin
[...]
end;
But ...
10-04-09 21:37:51 [*] Compiling Knife Server -> KnifeServer.pas...
10-04-09 21:37:51 [*] Knife Server -> [Error] (19:28): Type mismatch
10-04-09 21:37:51 [*] Compilation Failed.
10-04-09 21:37:51 Shutting down server...
-
You need ( ) because it does it this way atm:
1. Text = '!help' => boolean1
2. boolean1 OR Text => boolean or string operation => failure
-
The brackets weren't wrong.
if Text = '!help' then begin
if (Text = '!help') then begin
Both of these ways work.
Example for or, Here you need brackets!
if (Text = '!help') or (Text = '!Help') then begin
That's how you go, however heres a better solution:
if LowerCase(Text) = '!help' then begin
No matter how a player wrote !help, will it be !HeLp or !helP, it will be always executed.
-
you were missing begin and end; in the last post, that's what PIE fixed
-
type:
// Declare the type
type
TPlayer = Record
Task: byte; // I used task instead of Class because Class is a reserved word :/
end;
// Now create an array, one index slot for each player
var
Player: Array [1..32] of TPlayer;
// Looks like that when you use it:
procedure SetTask(ID, Task: byte);
begin
Player[ID].Task := Task;
end;
Now I only need to know what the hell you did there and how I can use it.
-
You don't need types as a beginner...
-
That didn´t help me much, Gizd.
I want to have different classes for different people.
-
// Declare the type
type // Use the type keyword so the compiler knows we are defining a type
TPlayer = Record // Tell the compiler the name of the type and what type the type will be (in this case, record)
Task: byte; // Write a list of variables to go with that type
Var2: string;
end; // end type decleration
// Now create an array, one index slot for each player
var
Player: Array [1..32] of TPlayer;
// Looks like that when you use it:
procedure SetTask(ID, Task: byte);
begin
Player[ID].Task := Task;
end;
Types are basically a way to re-use groups of variables, a type is itself used like a variable, with several sub-variables assigned to it.
In the example, the type is called TPlayer (T for type, and then the name of the variable it will be used on is a convention) and its sub-variables are Task and Var2.
What this means is that any variable that is of type TPlayer will have the sub-variables Task and Var2 assigned to it.
They can be accessed by dot notation, as shown in the line
TypedVar.SubVar
When used with arrays, make sure you treat the variable and the []'s as one, i.e TypedArray[index].SubVar, not TypedArray.[index]SubVar, or any other wierd ideas you may get.
So for example Types would be extremely useful if you had to manage several of the same variables for every player in a server
Type
TPlayer = record
Level: Byte;
LoggedIn: boolean;
Account: string;
Skills: string;
Power: Byte;
EXP: integer;
end;
var
Player: Array [1..32] of TPlayer
Information for each player can be accessed in a standard way
Player[12].Level
Player[3].LoggedIn
Player[7].Skills
-
Okay I went on and used the type function (which I didn´t find at this awesome webpage (http://www.enesce.com/help/) btw). I use some kind of AppOnIdle function combined with a timer that will force a knife to ones hand if they have a certain class. Still, I got some problems that could need explanations ...
The whole script (with line comments so it´s easier to read) is attached. For those who don´t like downloading here is a piece of my script:
procedure AppOnIdle(Ticks: Integer);
if (TPlayer.Klasse = Berserker) then begin
var
Timer: Integer;
Timer = 10;
if Timer > 0 then Timer := Timer -1
if Timer = 0 then begin
ForceWeapon(Player, 14, 255, 0);
Timer := 10;
end;
end;
14= Knife, 255= Fist, 0=default ammo. Before I used ...
type
TPlayer = Record
Klasse: byte;
end;
// Here I create an array for every player.
var
Player: Array [1..32] of TPlayer;
// This saves the players class in the variable Klasse
procedure SetKlasse(ID, Klasse: byte);
begin
Player[ID].Klasse := Klasse;
end;
-
Type is a core component of the language of pascal.
It is like saying I don't see 'end;' documented at enesce.com/help
Did you mean to make a const called beserker (with a number from 1 to 255)? If you did, you forgot it, if you didn't, you cant assign a string to a byte, and it wasn't a string anyway (no quotes).
-
Okay I changed Klasse from byte to string, but now it returns me this:
10-04-10 13:32:39 [*] Compiling Knife Server -> KnifeServer.pas...
10-04-10 13:32:39 [*] Knife Server -> [Error] (23:29): Type mismatch
10-04-10 13:32:39 [*] Compilation Failed.
10-04-10 13:32:39 Shutting down server...
Sorry, I really want to finish this project and I can´t wait :P
-
You need to change all other references to Klasse to string aswell.
Such as "procedure SetKlasse(ID, Klasse: byte);" -> "procedure SetKlasse(ID: byte;Klasse: string);"
You also need to change the "TPlayer.Klasse = Berserker;" line (under "!berserker") to "SetKlasse(ID,'Berserker');"
-
Upload your script again, then I'm gonna help you abit :]
-
Reupload. Changed the things EnEsCe mentioned but not more yet
The error changed a bit. Now it´s ...
10-04-10 16:21:12 [*] Compiling Knife Server -> KnifeServer.pas...
10-04-10 16:21:12 [*] Knife Server -> [Error] (23:11): Type mismatch
10-04-10 16:21:12 [*] Compilation Failed.
10-04-10 16:21:12 Shutting down server...
-
What mean that ?
if Timer > 0 then Timer := Timer -1
-
What mean that ?
if Timer > 0 then Timer := Timer -1
It's a timer, can't you see that ::)
Btw. you are missing a semicolon here (;)
procedure SetKlasse(ID, Klasse: String);
begin
Player[ID].Klasse := Klasse;
end;
procedure SetKlasse(ID: byte; Klasse: string);
That's correct, ID must be declared as a numeric parameter value.
(It would also work with integer/word, but since eC has byte too in all the other build-in things ppl use byte)
-
Hey DC! I'm not sure if you remember me, but anway, I'm gonna help ya :D
Check out the comments in the Script lines.
Hope I've helped :]
//Helping DarkCrusade..
//By Squiddy ~
//Note I didn't add any stuff in the OnPlayerSpeak Procedure, because I'm only helping you in the Berserker stuff. You can handle the commands and rules stuff ;]
Const //Setting some Global Constants..
Color = $FEDEBA; //Color to be used. This is my private color. Change it if you want :P
Var //Setting some Global Variants..
Klasse: Array[1..32] of String; //With this, you don't need the Type Record stuff. Usage: "Klasse[ID]"
Procedure OnPlayerSpeak(ID: Byte; Text: String);
Begin //Starts the Procedure..
Text := LowerCase(Text); //With this, you don't need to add "if Lowercase(Text) = '!berserker'". "Text := LowerCase(Text);" works for every text typed inside the OnPlayerSpeak Procedure.
if Text = '!berserker' Then Begin //If player types !Berserker..
WriteConsole(ID,'You are now a freaking berserker!',Color); //Then show this message to him.
Klasse[ID] := 'Berserker'; //Set his class to berserker..
end; //Ending the text function..
end; //Ending the procedure.
Procedure AppOnIdle(Ticks: Integer);
Var DC: Byte; //DC is a player's ID. Since AppOnIdle doesn't hold any ID, we have to create one. I used DC because of "DarkCrusade". It's a teaching proccess, it's very helpfull to use the student's initials. It helps student to assimilate stuff.
Begin
For DC := 1 To 32 Do if GetPlayerStat(DC,'Alive') = True Then Begin //"1 To 32" is to determine that DC is a player's ID. GetPlayerStat() stuff is to see if player is alive.
if Klasse[DC] = 'Berserker' Then Begin //Checks if his class is berserker..
if Ticks Mod 60 * 10 = 0 Then //Every 10 seconds...
ForceWeapon(DC,14,255,0); //The player receives a knife.
end; //Ending the Klasse Function..
end; //Ending the DC function..
end; //Ending the Procedure.
-
Sure I remember you, Squiddy, great time back then :) Thanks a lot for your help, now my script works perfectly and I even understood all the new stuff!
-
Sure I remember you, Squiddy, great time back then :) Thanks a lot for your help, now my script works perfectly and I even understood all the new stuff!
Glad I could help :]
Any other doubts, feel free to ask.
-
Well ... first of all: I get one knife every second and not every 10 seconds. I tried modifying the `Ticks Mod´ but it doesn´t change anything. Second: I tried killing a bot by throwing the knife but I wasn´t even able to kill myself. Stabbing works ... guess it´s caused by lags or stuff.
-
About the Damage stuff.. Add this to the Script:
Function OnPlayerDamage(Victim, Shooter: Byte; Damage: Integer): Integer;
Var DC: Integer; //DC is the ammount of damage that will be increased..
Begin //Starts..
if Klasse[Shooter] = 'Berserker' Then Begin //Checks is player's class is Berserker..
DC := Random(10,150); //Sets an value to DC to be added to the damage. It can be from 10 to 149.
Result := Damage + DC; //Adds DC to Damage..
end else Result := Damage; //Ending the Klasse Function. If Shooter's class isn't Berserker, the damage dealt will be the same.
end; //Ending the Function.
About the 10 Second stuff, try to replace this to the AppOnIdle Procedure:
Procedure AppOnIdle(Ticks: Integer);
Var DC: Byte; //DC is a player's ID. Since AppOnIdle doesn't hold any ID, we have to create one. I used DC because of "DarkCrusade". It's a teaching proccess, it's very helpfull to use the student's initials. It helps student to assimilate stuff.
Begin
For DC := 1 To 32 Do if GetPlayerStat(DC,'Alive') = True Then Begin //"1 To 32" is to determine that DC is a player's ID. GetPlayerStat() stuff is to see if player is alive.
if Klasse[DC] = 'Berserker' Then Begin //Checks if his class is berserker..
if Ticks Mod (60 * 10) = 0 Then //Every 10 seconds...
ForceWeapon(DC,14,255,0); //The player receives a knife.
end; //Ending the Klasse Function..
end; //Ending the DC function..
end; //Ending the Procedure.
Hope that helps/works. :]
If you have any doubts on how "else" works, it simply works like this:
Function OnPlayerDamage();
Begin //Starts..
if Klasse[Shooter] = 'Berserker' Then Begin //Checks is Shooter's class is Berserker
WriteConsole(Shooter,'You are a Berserker',$FFFFFF); //Send this message if Klasse[Shooter] is Berserker.
end else WriteConsole(Shooter,'You are so not a Berserker',$FFFFFF); //If Klasse[Shooter] isnt Berserker, send this.
end; //Ending the Function..
-
Great! This helped me much :) I am currently trying to find a balanced damage incremention for the random function. Is there a way to detect the nearest enemy foe that is not dead?
-
Great! This helped me much :) I am currently trying to find a balanced damage incremention for the random function. Is there a way to detect the nearest enemy foe that is not dead?
Sure there is!
Just need to use RayCast() and GetPlayerStat();
Here it goes..
[...] Some Procedure you may use.. //I don't know which one is it, so, fill this yourself.
Var S: Byte; Dist: Single; //S = Player's ID. I entered S because I have no idea if in that procedure there is already a 'DC' Byte, so I entered 'S' of Squiddy :P. Dist is the distance used in RayCast();
Begin //Starts..
For S := 1 To 32 Do if GetPlayerStat(S,'Alive') = True Then Begin //Checks is target player is alive..
if RayCast(GetPlayerStat(ID,'X'),GetPlayerStat(ID,'Y'),GetPlayerStat(S,'X'),GetPlayerStat(S,'Y'),Dist,800) = True Then Begin //Check is player S is visible for player ID..
[...] //Here go whatever you want to put it in..
end; //Ending the RayCast() Function..
end; //Ending the GetPlayerStat() Function..
end; //Ending the Procedure..
RayCast() Function checks if Player ID can see Player S. You have to determinate if its True or False.
-
Works great. Awesome that there is this Raycast function since I will add a Ninja class. Right now the DoDamage part looks like this:
// Do additional damage to the next enemy after the Berserker killed someone.
Procedure OnPlayerKill(Killer,Victim:byte;Weapon:byte);
begin
if Klasse[Killer] = 'Berserker' then begin
Var S: Byte; Dist: Single;
Begin
For S := 1 To 32 Do if GetPlayerStat(S,'Alive') = True Then Begin
if RayCast(GetPlayerStat(ID,'X'),GetPlayerStat(ID,'Y'),GetPlayerStat(S,'X'),GetPlayerStat(S,'Y'),Dist,800) = True Then Begin
DoDamage(S,Killer,50);
end;
end;
end;
But for some reason I get this error:
10-04-10 19:26:44 [*] Compiling Knife Server -> KnifeServer.pas...
10-04-10 19:26:44 [*] Knife Server -> [Error] (114:3): Identifier expected
10-04-10 19:26:44 [*] Compilation Failed.
10-04-10 19:26:44 Shutting down server...
I know I am dumb :S
-
http://devs.soldat.pl/wiki/index.php?title=Server_Scripting (http://devs.soldat.pl/wiki/index.php?title=Server_Scripting) ftw.
I'm quite sure you used eC's, it's not supporting the current server version anymore, the link above does.
Use DoDamageBy(Victim, Shooter, Damage); instead of DoDamage here
Beside a question, do you want to damage all players around the player or only the nearest?
-
Only the nearest. I don´t know why you used DoDamageBy(Victim,Shooter,Damage);. devs.Soldat says that it´s DoDamage(ID,Damage); ... I am so confused.
-
Well, with DoDamageBy you can specify which person deals damage to someone, with DoDamage it's just the player itself whos damaging hismelf afaik.
-
10-04-10 21:36:10 [*] Compiling Knife Server -> KnifeServer.pas...
10-04-10 21:36:10 [*] Knife Server -> [Error] (117:3): Identifier expected
10-04-10 21:36:10 [*] Compilation Failed.
10-04-10 21:36:10 Shutting down server...
For ...
Procedure OnPlayerKill(Killer,Victim:byte;Weapon:byte);
begin
if Klasse[Killer] = 'Berserker' then begin
Var S: Byte; Dist: Single;
begin
For S := 1 To 32 Do if GetPlayerStat(S,'Alive') = True Then Begin
if RayCast(GetPlayerStat(ID,'X'),GetPlayerStat(ID,'Y'),GetPlayerStat(S,'X'),GetPlayerStat(S,'Y'),Dist,800) = True Then Begin
DoDamageBy(S,Killer,50);
end;
end;
end;
-
Procedure OnPlayerKill(Killer,Victim:byte;Weapon:byte);
begin
if Klasse[Killer] = 'Berserker' then begin
Var S: Byte; Dist: Single;
begin
For S := 1 To 32 Do if GetPlayerStat(S,'Alive') = True Then Begin
if RayCast(GetPlayerStat(ID,'X'),GetPlayerStat(ID,'Y'),GetPlayerStat(S,'X'),GetPlayerStat(S,'Y'),Dist,800) = True Then Begin
DoDamageBy(S,Killer,50);
end;
end;
end;
It's because your style of coding sucks:
Procedure OnPlayerKill(Killer,Victim:byte;Weapon:byte);
begin
if Klasse[Killer] = 'Berserker' then begin
Var S: Byte; Dist: Single;
begin
For S := 1 To 32 Do if GetPlayerStat(S,'Alive') = True Then Begin
if RayCast(GetPlayerStat(ID,'X'),GetPlayerStat(ID,'Y'),GetPlayerStat(S,'X'),GetPlayerStat(S,'Y'),Dist,800) = True Then Begin
DoDamageBy(S,Killer,50);
end;
end;
end;
Also you can't declare vars inside function...
-
Well well, Gizd. I put the variables to the beginning and got some errors because of Raycast. Raycast didn´t change.
-
Why are you using rayCast to find the closest player?...
-
Try this with that procedure that Gizd mentioned.
Procedure OnPlayerKill(Killer,Victim:byte;Weapon:byte);
Var S: Byte; Dist: Single; //put variable declarations just after the definition of the procedure, but before the first begin
begin
if Klasse[Killer] = 'Berserker' then begin
For S := 1 To 32 Do if GetPlayerStat(S,'Alive') = True Then Begin
if RayCast(GetPlayerStat(ID,'X'),GetPlayerStat(ID,'Y'),GetPlayerStat(S,'X'),GetPlayerStat(S,'Y'),Dist,800) = True Then Begin
DoDamageBy(S,Killer,50);
end;
end;
end;
end;
-
I´m using Raycast, because it allows me to ignore vanished players. I will try working with your code, Spilt, thanks :)
EDIT: I screwed DoDamage. It seems not to work right now and I had a way better idea for the Berserker. Players that are in range (5-20 metres) of a player that was killed by a Berserker will get blown up immediatly.
Procedure OnPlayerKill(Killer,Victim:byte;Weapon:byte);
Var S: Byte; Dist,x,y: Single;
begin
if Klasse[Killer] = 'Berserker' then begin
For S := 1 To 32 Do if GetPlayerStat(S,'Alive') = True then begin
x := GetPlayerStat(S,'x');
y := GetPlayerStat(S,'y');
if not Raycast (x,y,x,y -3,Dist,20) then begin
CreateBullet(x,y,1,1,100,4,Killer);
WriteConsole(S,'You have just been blown up!', Color);
end;
end;
end;
end;
Right now my problem is, that no bullet is created OnPlayerKill. The server compiles and stuff so I don´t have an error log but the console tells me that there is an invalid parameter in my OnPlayerKill function.
-
Weapon: byte; -> Weapon: string;
DO NOT USE eC's MANUAL, ITS FOR THE NEXT SERVER VERSION NOT FOR THE CURRENT
USE THIS ONE TILL NEXT SERVER VERSION COMES OUT O_O (http://devs.soldat.pl/wiki/index.php?title=Server_Scripting)
Sry, but had to uppercase ;D Idk if you use it, but it looks like :|
-
*CAPSLOCK ON*
PROTIP: LEARN TO DO PROPER INDENTATIONS OR YOU WON'T FIND MISSING END'S / BEGIN'S
-
@Gizd: my script has proper indentations. The copy/paste thing made it look bad and so I changed it.
@Swompie: I will take a look at it.
FastEdit: LOL Swompie, I just changed what you mentioned and it compiles perfectly! ;D
SlowEdit: Everything is fine. The script compiles and stuff. But I cannot blow up any players ... I don´t know why it happens but I added more line comments to my script so it´s more readable and I marked the lines where I have this urgent problem. Also I added a command that makes testing easier. Type !bots to add 4 different bots ;)
Script attached.
-
Attached the script, drops a cluster on enemys in range of 20m, can cause epic explosion effects when lots of enemys are near you :D Ask when you don't understand sth.
-
Thank you very much, Swomp :) I modifyed the script again and added the Mage class (Berserker is finished). I think I messed some things up but I´m not sure. The Mage is granted one grenade for every kill and gains summoning power that allows him to summon a minion that will spawn on his team. The script doesn´t compile correctly so I guess it has something to do with the message. Here are the important lines:
Variables at the beginning:
var
Klasse: array[1..32] of string;
SmnPower: array[1..32] of byte;
Procedure OnPlayerSpeak for sure ;)
if LowerCase(Text) = '!mage' then begin
WriteConsole(ID,'#You are now a MAGE!', Color);
WriteConsole(ID,'#You are able to summon a minion when you have maximal', Color);
WriteConsole(ID,'#summoning power (10). You get power for killing enemies.', Color);
WriteConsole(ID,'#For every kill you gain one grenade, too!', Color);
Klasse[ID] := 'Mage';
end;
if LowerCase(Text) = '!summon' then begin
if SmnPower = 10 then begin
GetPlayerStat(ID,'Team');
Command('/addbot' + Team + ' Knife Minion');
WriteConsole(ID,'#You have summoned a minion! He will kill others for you!', Color);
end;
if SmnPower < 10 then begin
WriteConsole(ID,'#Your summoning power is too low to summon the minion.', Color);
end;
The timer for the Mage.
Procedure AppOnIdle(Ticks: Integer); var DC: Byte; begin
for DC := 1 to 32 do if GetPlayerStat(DC,'Alive') = true then begin
if Klasse[DC] = 'Mage' then begin
if Ticks Mod (60 * 7) = 0 then
ForceWeapon(DC,14,255,0);
end;
end;
OnPlayerKill procedure:
Procedure OnPlayerKill(Killer,Victim:byte;Weapon:string);
begin
if Klasse[Killer] = 'Mage' then begin
GiveBonus(Killer,4); SmnPower := SmnPower+1;
if SmnPower > 10 then begin
SmnPower := 10;
end;
WriteConsole(Killer,'You got a new grenade!',Color);
WriteConsole(Killer,'Your summoning power is ' + + '/10!',Color)
end;
end;
Sorry, it´s much code but I don´t know where I failed.
-
I think it's better you attach the code when you have a problem/need help in more parts of the script, also easier for me to point out errors faster than copying these pieces of code together :E
Heres the code:
In AppOnIdle Player loops you must always check if a players is active before doing anything else.
OnPlayerSpeak was almost right, but you was missing the variable team there, with that it had been:
Team := GetPlayerStat(ID, 'Team');
Command('/setteam' + inttostr(Team) + ' Knife Minion');
But you can save this variable and just use GetPlayerStat() in the Command() function itself, look in the code right now to see what I mean.
Aswell you were missing alot of the [ID] brackets. Added them. The ability of grenades will always give him the maximal amount of grenades, since there are also nade kits on all over the map, I would think about giving the mage a Clusters all 4 or 5 kills.
var
Klasse: array[1..32] of string;
SmnPower: array[1..32] of byte;
procedure OnPlayerSpeak(ID: byte; Text: string);
begin
if LowerCase(Text) = '!mage' then begin
WriteConsole(ID,'#You are now a MAGE!', Color);
WriteConsole(ID,'#You are able to summon a minion when you have maximal', Color);
WriteConsole(ID,'#summoning power (10). You get power for killing enemies.', Color);
WriteConsole(ID,'#For every kill you gain one grenade, too!', Color);
Klasse[ID] := 'Mage';
end;
if LowerCase(Text) = '!summon' then
if SmnPower[ID] >= 10 then begin
Command('/addbot' + inttostr(GetPlayerStat(ID, 'Team')) + ' Knife Minion');
WriteConsole(ID, 'You have summoned a minion! He will kill others for you!', Color);
end else WriteConsole(ID, 'You summoning power is too low to summon the minion.', Color);
end;
Procedure AppOnIdle(Ticks: Integer);
var DC: Byte;
begin
for DC := 1 to 32 do
if GetPlayerStat(DC, 'Active') = true then
if GetPlayerStat(DC, 'Alive') = true then
if Klasse[DC] = 'Mage' then
if Ticks Mod (60 * 7) = 0 then
ForceWeapon(DC,14,255,0);
end;
var
Klasse: array[1..32] of string;
SmnPower: array[1..32] of byte;
procedure OnPlayerSpeak(ID: byte; Text: string);
begin
if LowerCase(Text) = '!mage' then begin
WriteConsole(ID,'#You are now a MAGE!', Color);
WriteConsole(ID,'#You are able to summon a minion when you have maximal', Color);
WriteConsole(ID,'#summoning power (10). You get power for killing enemies.', Color);
WriteConsole(ID,'#For every kill you gain one grenade, too!', Color);
Klasse[ID] := 'Mage';
end;
if LowerCase(Text) = '!summon' then
if SmnPower[ID] >= 10 then begin
Command('/addbot' + inttostr(GetPlayerStat(ID, 'Team')) + ' Knife Minion');
WriteConsole(ID, 'You have summoned a minion! He will kill others for you!', Color);
end else WriteConsole(ID, 'You summoning power is too low to summon the minion.', Color);
end;
Procedure AppOnIdle(Ticks: Integer);
var DC: Byte;
begin
for DC := 1 to 32 do
if GetPlayerStat(DC, 'Active') = true then
if GetPlayerStat(DC, 'Alive') = true then
if Klasse[DC] = 'Mage' then
if Ticks Mod (60 * 7) = 0 then
ForceWeapon(DC,14,255,0);
end;
Procedure OnPlayerKill(Killer,Victim:byte;Weapon:string);
begin
if Klasse[Killer] = 'Mage' then begin
GiveBonus(Killer, 4);
SmnPower[Killing] := SmnPower[Killer] + 1;
if SmnPower > 10 then
SmnPower := 10;
WriteConsole(Killer, 'You got a new grenade!', Color);
WriteConsole(Killer, 'Your summoning power is ' + inttostr(SmnPower[Killer]) + '/10!', Color)
end;
end;
Not tested, but should work.
Oh, and a side note: remove these #, they're looking annoying ingame ;)
I will later give you a fancy procedure which creates a box around your text.
Also find try to find your indent style for soldat, I use 2-space-steps, works & looks good, alot of people also use TAB, but I think it's too much space. It's your decision [fist]
-
This returns me the error "Type Mismatch" ...
if smnPower > 10 then
SmnPower := 10;
... too bad :) Thanks for your advice ;)
-
Hint: Look at the variables you declared at the beginning, then this should be solved :]
-
How could I forget that ;D Anyway, still there is a bug:
Procedure OnPlayerKill(Killer,Victim:byte;Weapon:string);
begin
if Klasse[Killer] = 'Berserker' then begin
DropBombsInRange(Killer);
end;
if Klasse[Killer] = 'Mage' then begin
GiveBonus(Killer, 4);
WriteConsole(Killer, 'You got a new grenade!', Color);
SmnPower[Killer] := SmnPower[Killer] + 1;
if SmnPower[Killer] > 10 then begin
SmnPower[Killer] := 10;
end;
WriteConsole(Killer, 'Your summoning power is ' + inttostr(SmnPower[Killer]) + '/10!', Color);
end;
end;
end;
end;
The error is as follows:
10-04-11 16:12:43 [*] Compiling Knife Server -> KnifeServer.pas...
10-04-11 16:12:43 [*] Knife Server -> [Error] (188:2): 'BEGIN' expected
10-04-11 16:12:43 [*] Compilation Failed.
10-04-11 16:12:43 Shutting down server...
-
You've got too much ends in OnPlayerKill :E (2 too much if I counted right)
Btw.
Also find try to find your indent style for soldat, I use 2-space-steps, works & looks good, alot of people also use TAB, but I think it's too much space. It's your decision [fist]
;D Makes life sometimes easier, when you write it like this you can see faster if you miss an end or begin:
begin
| begin
| | begin
| | end;
| end;
end;
Got it what I mean? :p
-
Hmmm im not sure about what i will right but i think it should be like that
Procedure OnPlayerKill(Killer,Victim:byte;Weapon:string);
begin
if Klasse[Killer] = 'Berserker' then begin
DropBombsInRange(Killer);
end;
end;
Anyone can tell how we procede with begin and end; ?
because im not sure of what ive just write :S
-
For each begin you need an end;
For each end; you need a begin
-
So thats mean that the part of script that i have posted is right ?
PS:Swompie i send you a pm about that your server script has crashed ...:S
-
Yeah I totally got it ... I want the bot to get one knife ever 5 seconds now and he should throw it also. If this bot kills an enemy the summoner should get one point. The bot should be kicked after he died the second time.
@mich: Stupid you, it´s just like in my script ;)
-
Giev code then I add how to make that :E
-
No I want to do that by myself :( It´s my first real project, you know :P
EDIT:
Am I able to use HighestID to get the ID of the bot and save it as a variable that I am able to use for some kind of death clock?
-
Am I able to use HighestID to get the ID of the bot and save it as a variable that I am able to use for some kind of death clock?
Whaaaat?
If you paste one more code without proper indentations I won't come to help you anymore(so there will be only Swompie left what will result in major fail of your scripts) D:
@squiddy: ............
-
[...]
If you paste one more code without proper indentations I won't come to help you anymore(so there will be only Swompie left what will result in major fail of your scripts) D:
Swompie and me! :P
I've gone out yesterday for the whole day with my girlfriend, but now, I'm here for the rescue! :P
About the Bot thing, try this.
Procedure AppOnIdle(Ticks: Integer);
Var BotID: Byte; //BotID is the ID of the bot..
Begin //Starts..
For BotID := 1 To 32 Do if GetPlayerStat(BotID,'Human') = False Then Begin //Checkin if BotID is actually a bot..
if GetPlayerStat(BotID,'Deaths') < 2 Then Begin //Checking if BotID has less than 2 deaths..
if Ticks Mod (60 * 5) = 0 Then ForceWeapon(BotID,14,GetPlayerStat(BotID,'Secondary'),0); //Then give BotID a knife every second. I don't know if Knife's ID is 14, I just guessed :P
end else KickPlayer(BotID); //If BotID has more/equal 2 deaths, kick him..
end; //Ending the GetPlayerStat() Procedure..
end; //Ending the AppOnIdle Procedure.
-
Who cares about indentations if it´s only like that at the forum. Read my script and see my almighty indentations, Gizd ...
Yay, rescue!
-
Who cares about indentations if it´s only like that at the forum. Read my script and see my almighty indentations, Gizd ...
If you keep making begin-end mistakes they are not good.
(you ruined my 404 postcount :<)
-
Who cares about indentations if it´s only like that at the forum. Read my script and see my almighty indentations, Gizd ...
If you keep making begin-end mistakes they are not good.
(you ruined my 404 postcount :<)
Delete your last post! :D
Gonna make an example maybe later DC.
-
I didn´t force you to post, did I :P Will your vengeance be that you stop posting here? *almosthappy* :)
Thanks, Swomp [pigtail]
-
Case you, DC, havent noticed, check out my last post, I edited it and posted the Bot stuff.
-
I tried creating a function that will increase a players kill value if their minion kills someone and set the kill value of the bot to 0 again. Something must have gone wrong ...
10-04-11 20:09:51 [*] Compiling Knife Server -> KnifeServer.pas...
10-04-11 20:09:51 [*] Knife Server -> [Error] (218:1): Identifier expected
10-04-11 20:09:51 [*] Compilation Failed.
10-04-11 20:09:51 Shutting down server...
Happened after I modified lines 185-199. Script attached.
-
You missed an 'End;' at the end of the AppOnIdle Procedure..
Try this, it should work:
Procedure AppOnIdle(Ticks: Integer);
var BotID,DC: Byte;
begin
for DC := 1 to 32 do if GetPlayerStat(DC,'Alive') = true then begin // This is a timer that will force the Berserker a knife every 10 seconds.
if Klasse[DC] = 'Berserker' then begin // But only if he´s alive.
if ticks mod (60 * 10) = 0 then
ForceWeapon(DC,14,255,0);
end;
for DC := 1 to 32 do
if GetPlayerStat(DC, 'Active') = true then
if GetPlayerStat(DC, 'Alive') = true then
if Klasse[DC] = 'Mage' then
if ticks mod (60 * 7) = 0 then
ForceWeapon(DC,14,255,0);
for BotID := 1 to 32 do if GetPlayerStat(BotID,'Human') = false then begin //Checkin if BotID is actually a bot..
if GetPlayerStat(BotID,'Deaths') < 2 then begin //Checking if BotID has less than 2 deaths..
if GetPlayerStat(BotID,'Kills') > 0 then begin
SetScore(DC,GetPlayerStat(DC,'Kills') +1 );
SetScore(BotID,0);
if ticks mod (60 * 5) = 0 then
ForceWeapon(BotID,14,GetPlayerStat(BotID,'Secondary'),0); //Then give BotID a knife every 5 seconds.
end else KickPlayer(BotID); //If BotID has more/equal 2 deaths, kick him..
end;
for DC := 1 to 32 do if GetPlayerStat(DC,'Alive') = true then begin //The timer for the Thief class. Thieves get
if Klasse[DC] = 'Thief' then //one knife every 8 seconds.
if ticks mod (60*8) = 0 then
ForceWeapon(DC,14,255,0);
end;
for DC := 1 to 32 do if GetPlayerStat(DC,'Alive') = true then begin //The timer for the Ninja class. Ninjas get
if Klasse[DC] = 'Ninja' then //one knife every 8 seconds.
if ticks mod (60 * 8) = 0 then
ForceWeapon(DC,14,255,0);
end;
end;
end;
end;
-
This is weird. The script compiles but gets caught in an endless loop and kicks a player. Since there is no ... screen attached.
-
You had no indentifer for DC, so it kept kicking players.
I hope this works.
-
Same problem.
-
Try replacing this AppOnIdle(); then..
Procedure AppOnIdle(Ticks: Integer);
var BotID,DC: Byte;
begin
for DC := 1 to 32 do if GetPlayerStat(DC,'Alive') = true then begin // This is a timer that will force the Berserker a knife every 10 seconds.
if Klasse[DC] = 'Berserker' then begin // But only if he´s alive.
if ticks mod (60 * 10) = 0 then
ForceWeapon(DC,14,255,0);
end;
for DC := 1 to 32 do
if GetPlayerStat(DC, 'Active') = true then
if GetPlayerStat(DC, 'Alive') = true then
if Klasse[DC] = 'Mage' then
if ticks mod (60 * 7) = 0 then
ForceWeapon(DC,14,255,0);
for BotID := 1 to 32 do if GetPlayerStat(BotID,'Human') = false then begin //Checkin if BotID is actually a bot..
if GetPlayerStat(BotID,'Deaths') < 2 then begin //Checking if BotID has less than 2 deaths..
SetScore(DC,GetPlayerStat(DC,'Kills') +1 );
SetScore(BotID,0);
if ticks mod (60 * 5) = 0 then
ForceWeapon(BotID,14,GetPlayerStat(BotID,'Secondary'),0); //Then give BotID a knife every 5 seconds.
end else KickPlayer(BotID); //If BotID has more/equal 2 deaths, kick him..
end;
for DC := 1 to 32 do if GetPlayerStat(DC,'Alive') = true then begin //The timer for the Thief class. Thieves get
if Klasse[DC] = 'Thief' then //one knife every 8 seconds.
if ticks mod (60*8) = 0 then
ForceWeapon(DC,14,255,0);
end;
for DC := 1 to 32 do if GetPlayerStat(DC,'Alive') = true then begin //The timer for the Ninja class. Ninjas get
if Klasse[DC] = 'Ninja' then //one knife every 8 seconds.
if ticks mod (60 * 8) = 0 then
ForceWeapon(DC,14,255,0);
end;
end;
end;
Otherwise, I have no idea.
-
I did some testing: Script compiles and works fine except that the bot I summon is invincible and has no name. In addition I don´t get his kills, though they are set to 0 again. Bot kicking works also.
Bot file: Name: Minion.bot
[BOT]
Name=KnifeMinion
Color1=$FFFFFFFF
Color2=$FFFFFFFF
Skin_Color=$FFFFFFFF
Hair_Color=$FFFFFFFF
Favourite_Weapon=Knife
Secondary_Weapon=
Friend=
Accuracy=0
Shoot_Dead=0
Grenade_Frequency=100000000
Camping=255
OnStartUse=255
Hair=4
Headgear=1
Chain=0
Chat_Frequency=10000000000
Chat_Kill=Are you proud of me, master?
Chat_Dead=See you ... in a while.
Chat_Lowhealth=Food ... give me ... foood!
Chat_SeeEnemy=A knife in the right moment can change everything!
Chat_Winning=See, I can serve my master well.
He shouldn´t talk at all and should throw his knife (but currently he doesn´t).
-
Weapon has to be Combat Knife :P
You can disable bot chat in soldat.ini, it's on bottom of file.
-
Do you mean chat frequency? It doesn´t work, the bot will say "Flag!" and "Drop your Weapon!" anyway (it´s in the font folder).
-
You need to edit it in Soldat.ini
[BOTS]
Difficulty=10
Chat=0
From 1 to 0, aye.
If you want bots to say stuff at some points you can use the BotChat (http://enesce.com/help/html/Functions/BotChat.html) function.
-
That solved it, croat. Thank you :)
But still, the bot is invisible and has no name ... and I don´t get any points from him.
-
[BOT]
Name=KnifeMinion
Color1=$FFFFFFFF
Color2=$FFFFFFFF
Skin_Color=$FFFFFFFF
Hair_Color=$FFFFFFFF
Favourite_Weapon=Knife
Secondary_Weapon=Knife
Friend=
Accuracy=0
Shoot_Dead=0
Grenade_Frequency=7
Camping=255
OnStartUse=255
Hair=4
Headgear=1
Chain=0
Chat_Frequency=0
Chat_Kill=Are you proud of me, master?
Chat_Dead=See you ... in a while.
Chat_Lowhealth=Food ... give me ... foood!
Chat_SeeEnemy=A knife in the right moment can change everything!
Chat_Winning=See, I can serve my master well.
You need to make sure that the numbers are valid, no enormous numbers and no empty lines.
-
Bot which spawns with a knife and throws a knife:
Favourite_Weapon=Combat Knife
Secondary_Weapon=1
-
--Last post deleted-- (I don´t like doubleposting)
So I cannot use the ninja class since one part of the ninja function doesn´t work. The problem part is this one ...
Procedure OnFlagScore(ID,Teamflag:byte);
begin
if Klasse[ID] = 'Ninja' then begin
GiveBonus(ID, 1);
WriteConsole(ID,'############################################################',Color);
WriteConsole(ID,'You are granted 25 seconds predator time for scoring!', Color);
WriteConsole(ID,'############################################################',Color);
end;
end;
Well, help me fixing it or give me a brandnew idea for a better class ;)
-
What the? I don't see anything wrong there. Maybe you assigned the Klasse var somewhere wrong.
Otherwise, no idea, actually it should work :| (And please remove the ###'s, gah can't see them :o)
-
What is the ID of the flamer? For my new class I need a ForceWeapon function ...
procedure OnPlayerSpeak(ID:Byte;Text:String);
begin
[...]
// Engineer (choose class)
if LowerCase(Text) = '!engineer' then begin
WriteConsole(ID,'You are now a ENGINEER! (special command: !gun' Color);
WriteConsole(ID,'For 5 kills you are able to get a special gun for 20 seconds!', Color);
Klasse[ID] := 'Engineer';
end;
// Special gun (for Engineer)
if LowerCase(Text) = '!gun' then begin
ForceWeapon(ID,{FlamerID},0,0);
WriteConsole(ID,'You got your special weapon ready to your hands!', Color);
end;
[...]
end;
-
Try this:
ForceWeapon(ID,11,0,0);
Flamer ID is 11.
-
Thank you, where can I find the ID list?
-
In the core.pas (default) as consts.
-
Ah thanks. I don´t get around the problem with the KnifeMinion so I removed it and instead the player gets full health for killing someone. I got a problem with a little function for the Engineer. Here is the log ...
10-04-14 16:53:34 [*] Knife Server -> [Error] (221:44): Close round expected
10-04-14 16:53:34 [*] Compilation Failed.
10-04-14 16:53:34 Shutting down server...
And here the procedure.
Procedure AppOnIdle(Ticks: Integer);
var DC: Byte;
begin
[...]
// Engineer (1 knife / 7 seconds)
for DC := 1 to 32 do
if GetPlayerStat(DC, 'Active') = true then
if GetPlayerStat(DC, 'Alive') = true then
if Klasse[DC] = 'Engineer' then
if ((GetPlayerStat(DC, 'Primary')) Primary = 11) = false then
if ticks mod (60 * 7) = 0 then
ForceWeapon(DC,14,255,0);
end;
end;
end;
-
if GetPlayerStat(DC, 'Primary') <> 11 then
-
10-04-14 16:53:34 [*] Knife Server -> [Error] (221:44): Close round expected
10-04-14 16:53:34 [*] Compilation Failed.
10-04-14 16:53:34 Shutting down server...
Why don't you read the god damned error? It clearly says that there is a close round "( )" mistake in line 220 column ~44.
-
Well, now I know at least, Gizd :P And I read it. I didn´t know how to create a timer that displays the text like I´ve seen somewhere else so I tried this:
AppOnIdle procedure
// Special Gun (duration = 5 seconds)
for DC := 1 to 32 do
if GetPlayerStat(DC, 'Alive') = true then
if Klasse[DC] = 'Engineer' then
if ticks mod (60 * 5) = 5 then
DrawText(DC,'5 seconds left',60,Color,(255,255,255),5,50);
if ticks mod (60 * 5) = 4 then
DrawText(DC,'4 seconds left',60,Color,(255,255,255),5,50);
if ticks mod (60 * 5) = 3 then
DrawText(DC,'3 seconds left',60,Color,(255,255,255),5,50);
if ticks mod (60 * 5) = 2 then
DrawText(DC,'2 seconds left',60,Color,(255,255,255),5,50);
if ticks mod (60 * 5) = 1 then
DrawText(DC,'1 second left',60,Color,(255,255,255),5,50);
if ticks mod (60 * 5) = 0 then
DrawText(DC,'Gun removed',60,Color,(255,255,255),5,50);
ForceWeapon(DC,14,14,0);
Darn I hope I could fix all those bugs myself. Note for Gizd: Yeah, it´s the same error. Hurr. Hurr.
10-04-14 19:23:06 [*] Knife Server -> [Error] (230:46): Close round expected
10-04-14 19:23:06 [*] Compilation Failed.
10-04-14 19:23:06 Shutting down server...
-
Dear lord that's ugly.. Let me give a shot at teaching you a bit and let's go over your code. I'm assuming this is in AppOnIdle
And please use 2 spaces for indentations and not tabs. Tabs suck, they're being treated differently all the time. A space is always a sincle char space.
// Special Gun (duration = 5 seconds)
for DC := 1 to 32 do
if GetPlayerStat(DC, 'Alive') = true then
So, you're checking wether all 32 players are alive every second? Are you sure that's needed?
if Klasse[DC] = 'Engineer' then
if ticks mod (60 * 5) = 5 then
DrawText(DC,'5 seconds left',60,Color,(255,255,255),5,50);
Now this piece of code work every 5th second, if a player is alive and an engineer.
if ticks mod (60 * 5) = 4 then
DrawText(DC,'4 seconds left',60,Color,(255,255,255),5,50);
if ticks mod (60 * 5) = 3 then
DrawText(DC,'3 seconds left',60,Color,(255,255,255),5,50);
if ticks mod (60 * 5) = 2 then
DrawText(DC,'2 seconds left',60,Color,(255,255,255),5,50);
if ticks mod (60 * 5) = 1 then
DrawText(DC,'1 second left',60,Color,(255,255,255),5,50);
if ticks mod (60 * 5) = 0 then
DrawText(DC,'Gun removed',60,Color,(255,255,255),5,50);
ForceWeapon(DC,14,14,0);
You forgot to use begin-end. That's a pity cause i explained it when you started this topic.. because it's hella important.
If..then (as well as many other commands) will BY DEFAULT only read the next line as statement (statement = what happens after then). So basically above code will be calle EVERY apponidle. And DC will ALWAYS be 32 because the loop ended. Basically the 32th player will be harrased with a message almost every second, and his weapon will be forced EVERY second.
Honestly It's not clear to me what you're trying to accomplish here. But I'm sure it'll be easier to simply add a global variable to the script and call it EngineerTimer or something. Then use apponidle to increase/decrease it every second and make something like:
If EngineerTimer < 6 then begin
if EngineerTImer < 1 then begin
EngineerTimer = STARTTIME;
//remove gun
end else
DrawText(DC,inttostr(EngineerTimer)+' second left',60,Color,(255,255,255),5,50);
end;
EngineerTimer := EngineerTimer - 1;
Good luck DC, but to be honest I'm starting to get the impression you're not really a coder.. That's a bit personal, because I think programming requires more talent than practice. Oh, you shouldn't mind me too much ;)
-
Pfft, nvm JFK was faster :D
You need to use RGB(R, G, B);
For the timer you need a var.
To display it:
if (TimerVar < 6) and (TimerVar > 0) then // If you set the first number to 11 it would display 10..1 seconds; the 0 is there so it doesn't say "0 seconds left"
DrawText(DC, inttostr(TimerVar) + ' seconds left', 180, Color, RGB(255,255,255), 50, 300); // Delay: 1 second = 60 ticks :D, it should be atleast sth. around 3 seconds
if TimerVar = 0 then // check if timer var is zero and say the gun was removed
DrawText(DC, 'Gun removed..', 180, Color, RGB(255,255,255), 50, 300);
-
Swompie, all good, except you dont have to use "if (TimerVar < 6) And (TimerVar > 0)"..
Just go..
AppOnIdle();
Begin
if TimerVar > 0 Then Begin
DrawText();
end else if TimerVar = 0 Then Begin
DrawText();
end;
end;
Simple like that, instead of using lots of And's..
Personally, I rather using "Then if"s instead of And's.. It looks way better without the () stuffs..
Oh well, it's just my opinion about it :P Please don't throw any rocks at me :D
-
Never saw such an error before ...
10-04-14 21:18:32 [*] Knife Server -> [Error] (232:18): Assignment expected
10-04-14 21:18:32 [*] Compilation Failed.
10-04-14 21:18:32 Shutting down server...
I tried JFKs method and worked a bit on it and it should work but it doesn´t. I really don´t know what´s wrong.
procedure AppOnIdle(Ticks: Integer);
var DC,StartTime: Byte;
EngineerTimer: Integer;
begin
for DC := 1 to 32 do
if EngineerTimer < 6 then begin
if EngineerTImer < 1 then begin
EngineerTimer = STARTTIME;
ForceWeapon(DC,14,14,0);
DrawText(DC, 'Gun removed', 120,Color,(255,255,255),5,50);
end else
DrawText(DC,inttostr(EngineerTimer)+' second left',180,Color,(255,255,255),5,50);
end;
EngineerTimer := EngineerTimer - 1;
end;
end;
-
Do you have any brain?
EngineerTimer = STARTTIME;
-
The fuck now I have really no idea. The specific line includes "end;" and nothing else. What is this caused by?
10-04-14 21:34:09 [*] Knife Server -> [Error] (234:46): Close round expected
10-04-14 21:34:09 [*] Compilation Failed.
10-04-14 21:34:09 Shutting down server...
I have a brain but I am a little bit tired after all ... don´t ask.
-
Why don't you just paste line 233?
-
DrawText(DC,'Gun removed',120,Color,(255,255,255),5,50);
-
See? Much better. What's that (255,255,255) meant to be?
-
I took it from here. (http://devs.soldat.pl/wiki/index.php?title=DrawText)
-
Yours:
DrawText(0,'xxx',120,Color,(255,255,255),5,50);
Wiki:
DrawText(0,'xxx',330,RGB(255,255,255),0.20,40,240);
-
One fixed, one new, but somewhere else:
Procedure OnPlayerKill(Killer,Victim:byte;Weapon:string);
var HP: Integer;
begin
if Klasse[Killer] = 'Mage' then begin
GiveBonus(Killer, 4);
GetPlayerStat(Killer,'Health'); <<< this is line 267
if 'Health' <> 0 = false then begin
HP := 150 - 'Health';
DoDamage(Killer,HP);
end;
end;
end;
And this is the log:
10-04-14 22:02:39 [*] Knife Server -> [Error] (267:19): Type mismatch
10-04-14 22:02:39 [*] Compilation Failed.
10-04-14 22:02:39 Shutting down server...
-
Swompie, all good, except you dont have to use "if (TimerVar < 6) And (TimerVar > 0)"..
Just go..
AppOnIdle();
Begin
if TimerVar > 0 Then Begin
DrawText();
end else if TimerVar = 0 Then Begin
DrawText();
end;
end;
Simple like that, instead of using lots of And's..
Personally, I rather using "Then if"s instead of And's.. It looks way better without the () stuffs..
Oh well, it's just my opinion about it :P Please don't throw any rocks at me :D
Yeah, actually your're right, thx for this :p I will never learn out :D
DC:
Close Round Excepted -> ( or ) missing
Assignment expected -> :=
-
GOD! 'Health' <> 0 - Does that make any sense to you?
@swompie: I think he understands that after I pointed it out few times(however that'd be assuming that he uses brain...).
-
@Gizd: That was added 30 seconds before I posted and I didn´t test it yet but you are right. It doesn´t make any sense at all. Though it doesn´t change anything. Same error.
@Swompie: Okay thanks, but what is "Type mismatch" in this case?
-
Oh I see...
GetPlayerStat(Killer,'Health');
Please explain what is that meant to do.
-
I want to set the players health back to 150 when he kills someone. I used GetPlayerStat(Killer,'Health') to get his current health, then I subtract the current health from 150 and the negative damage (found one little bug that doesn´t change the error when typing this) is dealt to the player.
-
@ JFK: are you sure that modulus business with ticks is right? How can you get 5, 4, 3, 2 or 1 when ticks is always a multiple of 60? Oo
-
@ JFK: are you sure that modulus business with ticks is right? How can you get 5, 4, 3, 2 or 1 when ticks is always a multiple of 60? Oo
To do something each second, you have to use "If Ticks Mod 60 = 0"..
If you use "If Ticks Mod (60 * 5) = 0", it will execute the function inside it, every FIVE seconds.
At the topic..
DarkCrusade, "Type Mismatch" is when you have an Integer, for instance, and you paste it at a String local.
For instance, assuming "MyInteger has a value of 150".
WriteConsole(ID,MyInteger,$FFFFFF);
Would go wrong. You have to do:
WriteConsole(ID,IntToStr(MyInteger),$FFFFFF);
IntToStr() converts an Integer into a String value.
StrToInt() converts an String into a Integer value.
I don't see any errors on what you pasted here.
Oh well, hope you have learned the 'lesson' :P
Also, one more thing. If Log says there is an error on line 267, there is an error on line 266. Don't know why, but it's just like that. One line less.
-
To do something each second, you have to use "If Ticks Mod 60 = 0"..
If you use "If Ticks Mod (60 * 5) = 0", it will execute the function inside it, every FIVE seconds.
thansk, i thought i was getting old
@ dc: GetPlayerStat(Killer,'Health');
thefuck is that? getplayerstat is a function, meaning it returns a value. This taken into account, you usually want to save that value into a variable to use it somewhere later on. You're not doing that when you seriously should
if 'Health' <> 0 = false then begin
again, what the fuck? 'Health' is a string - it's just a piece of text. It can't do anything. And you're trying to compare it to a number. Of-fucking-course it will give you a type mismatch error, you can't compare fruits with people (although sometimes i think you might actually be a papaya or something)
Gizd asked you these questions above, but i guess you didn't understand what he meant. Now if you're uncomfortable even with such things like "variable", i would like to kindly ask you to get the fuck out of here and go read some pascal manuals. Come back when you've learnt something about syntax and stuff. Thanks.
-
Don´t be rude man ... if you don´t have the patience refrain from posting. Anyway, thanks for your advice. Your third quote of my code was fixed one day ago and I already explained what went wrong. Again, don´t be rude just because I am a newbie to Pascal.
I got the script running again. Did some fixes. Found a bug ... the Engineers AppOnIdle function doesn´t work. Here is the part the bug occurs:
Procedure AppOnIdle(Ticks: Integer);
var DC, StartTime: Byte;
begin
for DC := 1 to 32 do
if GetPlayerStat(DC, 'Active') = true then
if GetPlayerStat(DC, 'Alive') = true then
if Klasse[DC] = 'Engineer' then
if GetPlayerStat(DC, 'Primary') <> 11 = false then
if ticks mod (60 * 7) = 0 then
ForceWeapon(DC,14,255,0);
end;
If the player is active, alive, an Engineer and his weapon is not a flamer he gets one knife every 7 seconds.
-
Procedure AppOnIdle(Ticks: Integer);
var DC, StartTime: Byte;
begin
for DC := 1 to 32 do
if GetPlayerStat(DC, 'Active') = true then
if GetPlayerStat(DC, 'Alive') = true then
if Klasse[DC] = 'Engineer' then
if GetPlayerStat(DC, 'Primary') <> 11 = false then //rethink this line
if ticks mod (60 * 7) = 0 then
ForceWeapon(DC,14,255,0);
end;
You're checking to see if the player's primary is not equal to 11, and then giving them a knife when that entire statement is false. In other words, you force their weapon to be a knife whenever they have a flamer.
-
dc, you're missing a lot of basic knowledge. People are pretty much wasting time explaining to you what the simplest things are, when you could go and read a tutorial peacefully. Then come here when you have troubles with actual scriptcore-specific stuff
-
If you´d had said that the way you did now there would be not much of a problem. You are right when you say that I miss a lot of knowledge, but I´m getting into it I think.
EDIT: Basically my script is ready. I already fixed all bugs (5 without asking, what do you say now :P) and worked on the balance of the classes. Right now there are 5 classes that have really different gameplay. Now I need a host for the script to test it with real players since I cannot host it on my home computer because of my WLAN connection ... any free server hosting services around?
-
Wish I could help you, but I am brazilian, and if you guys entered my server, it would be laggy.
Plus, my computer is broken. I am typing now from my mom's notebook.
Congratulations about your Script :)
Gonna test it someday :D
-
This is an urgent problem. The server expects an identifier in line 182:1 but the script doesn´t include any errors and should be working. The things I changed were changing the name of Berserker to Crusher, Mage to Alchemist, adding lowered damage for the Crusher and "exploding" knives for the Alchemist.
Function OnPlayerDamage(Victim, Shooter: Byte; Damage: Integer): Integer;
var Dam,Chance: Integer; <<<<<<<<<<<<<<<<< THIS LINE
begin
// Crusher (additional damage(10-15))
if Klasse[Shooter] = 'Crusher' then begin
Dam := Random(10,15);
Result := Damage + Dam;
end else Result := Damage;
// Crusher (additional damage(10-15))
if Klasse[Victim] = 'Crusher' then begin
Dam := Random(10,15);
Result := Damage - Dam;
end else Result := Damage;
// Thief (additional selfdamage)
if Klasse[Victim] = 'Thief' then begin
Dam := Random(5,25);
Result := Damage + Dam;
end else Result := Damage;
// Alchemist (exploding knives)
if Klasse[Shooter] = 'Alchemist' then begin
Chance := Random(1,2);
if Chance = 1 then begin
CreateBullet(GetPlayerStat(Victim,'x'), GetPlayerStat(Victim,'y') - 500, 0, 0, 100, 4, Shooter);
end;
end;
-
Can you send the whole script because i dont know where is the line 182:1
-
I marked the line. I won´t upload the whole script until the next version is ready.
-
Hmmmm which line get an error ?
-
Out of my expierence you may forgot a begin/end above OnPlayerDamage; Actually not 100% sure, but look if it is so :p
-
Hmmmm which line get an error ?
I marked the line.[...]
Learn to read.
If it says 182 the error is in 181 so you forgot an end.
-
Chance := Random(1,2);
if Chance = 1 then begin
This will always true since Random(Min, Max: integer) will never return the actual set Max value.
Use Max + 1 to prevent that.
-
@Swompie: In addition, for note, I think (not 100% certain) next scripting core, max value is included in the Random function.
-
Thanks for the advice. After that little issue in line 182 I fixed a number of bugs and now the script is working again perfectly :)
-
Damn, Swompie was faster :P
He is correct though. Random(Min, Max) will return all values from Min to Max - 1.
For instance, Random(1,2); would return 1 and 1.
Random(1,3); would return 1 and 2.
See what we mean ?
And, you did miss an end back there.
Try using NotePad++ to prevent this kind of errors. It's awesome.
-
I´m arleady using that stuff and fixed all bugs, thanks :) (and I understand the thing about Random ;) )
-
Good :]
I just posted it there in case you didn't.
I like to cover all possibilities :P
Any more questions/doubts, feel free to ask :D
-
So I want to practice more but I´m running out of ideas. I have some other projects going but before I go on with them I must learn some more of Soldat Pascal. Any ideas what I could do?
-
do a barrel roll.
But seriously, if you have completely no ideas, rip something off. Something you like and know well. Like FF or smth. At least it'll keep you entertained and motivated for some time
-
Had after all some ideas:
- Mountain climbing script (save/load (no buddy system), health restore)
- PunishBot (kicks spammers and bans them for x minutes (nearly finished)
-
If you need help, I can help you.
Plus, I've made a Buddy Script a few weeks ago.
I'd be glad to help ya :)
-
Thank you, man :)
-
- PunishBot (kicks spammers and bans them for x minutes (nearly finished)
You know there's a built-in anti-flood?
-
Yeah, you´d have a hang of what it will be like if I´d post what I´ve got until now. It´s WAY different.
From: April 18, 2010, 08:13:16 am
This is so basic that I am confused that it´s not working like this, because it should work to 100% ...
procedure OnJoinTeam(ID,Team:Byte);
begin
if Team = 4 then begin
Command('/setteam5 ' + ID); <<<- THIS LINE RETURNS THE ERROR
WriteConsole(ID,'Do not try to join the mutants. Please choose an other faction!', Red);
WriteConsole(ID,'To see which factions are available and other commands type !help', Red);
end;
end;
As soon as I remove ID it´s working. I used Command like this before and it worked. Is it not working with this specific procedure? (Error = Type Mismatch)
-
http://forums.soldat.pl/index.php?topic=37855.msg462039#msg462039
-
Next question: Why do I blame myself? ;D
-
Next question: Why do I blame myself? ;D
because you should
-
Dnmr is correct, DC.
Type Mismatches are errors that result when you have an integer value inside a string local, and vice-versa.
Also happens with float, and stuff.
Oh, well. Learn that. :P
Any more questions, feel free to ask :]
-
There's something weird with GiveBonus
I'm using GiveBonus with OnPlayerRespawn procedure. I can't say it doesn't work - as the result I can see 'Berserker Mode', 'Cluster nades', 'Predator mode', but I don't get these bonuses actually...
wtf?
-
There's something weird with GiveBonus
I'm using GiveBonus with OnPlayerRespawn procedure. I can't say it doesn't work - as the result I can see 'Berserker Mode', 'Cluster nades', 'Predator mode', but I don't get these bonuses actually...
wtf?
onplayerrespawn is called before the player actually respawns. You'll need to set a flag var and give the bonus in AppOnIdle right after the player respawns
-
Thanks!
-
Is OnJoinGame called before OnJoinTeam?
And is there any possible way to disable more than one weapon with one line?
Solved (figured it out myself).
-
Is OnJoinGame called before OnJoinTeam?
Try it yourself, put in these two proc, then write a msg which says which proc. was called, the first text appearing is the faster one. :P
-
Compiles, but there is an OutOfRange error OnMapChange and I don't know what could have caused it, any thoughts?
Procedure OnMapChange(NewMap: String);
var PlaID: Integer;
begin
for PlaID := 1 to 32 do
Spamming[PlaID] := 0;
if Warning[PlaID] > 0 then begin
Warning[PlaID] := 0;
WriteConsole(PlaID,'Your warning level was reset', Green);
end;
end;
-
Out of range -> You are trying to access an index of an array which doesn't exists.
-
PlaID has to be an array of integers or sth like that. Not just an integer.
You didnt define Warning and Spamming.
-
PlaID has to be an array of integers or sth like that. Not just an integer.
You didnt define Warning and Spamming.
Then it'll say it's missing vars.
He just forgot to put an begin in the loop.
-
He just forgot to put an begin in the loop.
Not really, he just forgot to check is PlaID is on server.
OnMapChange();
For PlaID := 1 To 32 Do if GetPlayerStat(PlaID,'Active') = True Then
{ Statements }
End;
-
What is the best way to check a teams score? Because I've already tried different things with no real result other than that it failed. Also one of my admin commands worked before I summarized a procedure (pretty basic command, should work that way).
Necessary parts:
var
ShowDmg: Boolean;
Function OnPlayerDamage(Shooter,Victim:Byte; Damage:Integer): Integer;
begin
case GetPlayerStat(Shooter,'Human') of
true: [...]
false: [...]
end;
case GetPlayerStat(Victim,'Human') of
true: [...]
false: [...]
end;
if Player[Shooter].ShowDmg = true then
WriteConsole(Shooter,'Output: ' + inttostr(Result), Red);
if Player[Victim].ShowDmg = true then
WriteConsole(Shooter,'Input: ' + inttostr(Result), Red);
end;
And:
Function OnCommand(ID:Byte; Text:String):boolean;
var Piece1,Piece2,Piece3: String;
Temp2,Temp3: Integer;
begin
Piece1 := GetPiece(Text,' ', 0);
Piece2 := GetPiece(Text,' ', 1);
Piece3 := GetPiece(Text,' ', 2);
Temp2 := strtoint(Piece2);
Temp3 := strtoint(Piece3);
case Piece1 of
'/showdmg': begin
Player[ID].ShowDmg := not Player[ID].ShowDmg;
WriteConsole(ID,'I/O messages got '+iif(Player[ID].ShowDmg=true,'enabled','disabled'),Black);
end;
[...]
end;
The script has a size of ~1350 lines right now.
-
Var ShowDmg: Boolean;
Player[Shooter].ShowDmg; //This shouldn't work, because ShowDmg is a Global Variant, not an Array.
//~~~~~~~~~~~~~~~~~~~~~~
//To make that work, do this:
Type DC = Record
ShowDmg: Boolean;
end;
Var
Player: Array[1..32] of DC;
{ Statements }
if Player[Shooter].ShowDmg = True; //Now we're talking about it!
//~~~~~~~~~~~~~~~~~~~~~~~~
//Although, if you are going to make only that Array, this should be faster and easier:
Var
ShowDmg: Array[1..32] of Boolean;
{ Statements }
if ShowDmg[Shooter] = True; //Faster, if you only have one Array.
//Is a waste of time to create a Type Function for one Array.
Aaanyway....
@Topic:
This should work:
Function GetTeamScore(Team: Byte): Integer;
Var DC: Byte;
Begin
For DC := 1 To 32 Do if GetPlayerStat(DC,'Team') = Team Then Begin
Result := GetPlayerStat(DC,'Flags');
end;
end;
//I'm sure you can come up with some Command that activates GetTeamScore() Function. :)
//Good luck :D
-
@boolean issue: Sorry, I already did it like that. I have a big type for that stuff ...
Uhm ... could you explain me what 'GetPlayerStat(DC,'Flags');' returns? Because I looked it up at devs.soldat and didn't find it..
-
NEVER, NEVER USE = true OR = false AGAIN EXCEPT FOR GetPlayerStat() STUFF.
When will people finally learn it ::)
You fail Squiddy, besides that you forgot to check if the players are active the loop is really useless, wherefore is case and these TeamScore variables ::)
function GetTeamScore(Team: byte): integer;
begin
case Team of
1: Result := AlphaScore;
2: Result := BravoScore;
3: Result := CharlieScore;
4: Result := DeltaScore;
end;
end;
As for the command:
case LowerCase(Piece1) of
'/showdmg': begin
Player[ID].ShowDmg := not Player[ID].ShowDmg;
WriteConsole(ID, 'Damage displaying is now ' + iif(Player[ID].ShowDmg, 'enabled', 'disabled'), $FFFFFF);
end;
end;
This is the shortest and best way.
OnPlayerDamage():
if Player[Shooter].ShowDmg then WriteConsole(Shooter, 'Base Dmg: ' + inttostr(Damage) + ' Out: ' + inttostr(Result) + ' dmg.' Red);
if Player[Victim].ShowDmg then WriteConsole(Victim, 'Base Dmg: ' + inttostr(Damage) + ' In: ' + inttostr(Result) + ' dmg.' Red);
Regards Swompie.
-
You fail Squiddy, besides that you forgot to check if the players are active the loop is really useless, wherefore is case and these TeamScore variables ::)
If you check Teams, means the player is already Active.
At least, that's what I think. I bearly have time to test my own Scripts, even less to test other people's ones :\
In regards to the "= True/= False" stuff, I don't really care. I learned that way, and don't expect me to change it that soon. :)
About the Case() Stuff..
Why would you use it, since you can do GetTeamScore(1) and it returns Alpha's Score ?
Well, I don't think you got my point. Kinda hard to explain. I just believe you don't need any variables.
Oh well.
-
The player at the start may be active, but if you check all 32 IDs with a loop you should at least check whether he's active or not, am I right?
-
The player at the start may be active, but if you check all 32 IDs with a loop you should at least check whether he's active or not, am I right?
Check it if you want, I just thought that checking teams, player would be automatically active.
-
Well, but what team would a player be in when he is not active? :/
As for case and the variables again:
It is much faster a loop from 1 to 32 which checks if he's in the right team, then gets his flag scores, and adds it to the result (which you actually didn't do, I just noticed that).
Anyway, I think you need to know that I like to say people how they could to improve their script much more, ask DC if you don't trust me xD.
-
Swompie, I think I got it now.
"AlphaScore, BravoScore" etc. Are Already-Existing-Values ?
I thought you were creating them, so it would be much more complex.
Indeed, it is quite better to use Case Of on that case.
Oh well, I know how you say people how they could improve their Scripts, and I understand that, it's very good when you do that :)
Thanks us for the lesson :P
-
Please don't blame me for the shitty indentations. The forum is doing something really weird with them ... No idea. I'm struggling with this piece of code a little and cannot help myself with it.
I have 4 different teams, every team has different weapons and abilitys, the last team (Delta) is a bot team which shouldm't get any points for killing, hence the last lines. My problem is, that whatever I try to check the kills with, it doesn't work. There is a mapchange feature to avoid color bugged and not kicked bots and additional weapons for teams that reached a certain score. Alpha,Bravo,Charlie and DeltaScore are built-in variables that should be accessable all time ...
const
MapGap = 100;
WepGap = 50;
var
WepTemp,Wave,Msg: Byte;
W1,W2,W3,MapChange: Boolean;
Procedure KickBots();
var BotID: Integer;
begin
for BotID := 1 to 32 do
if GetPlayerStat(BotID,'Human') = false then begin
Command('/kick ' + inttostr(BotID));
end;
end;
// Additional weapons for teams with more than 50 points
Procedure AllowWeapon();
var ID: Byte;
begin
for ID := 1 to 32 do
if GetPlayerStat(ID,'Active') then
case WepTemp of
1: begin
SetWeaponActive(ID,8,true);
DrawText(ID,'Your team got a new weapon!',180,White,0.06,160,200);
end;
2: begin
SetWeaponActive(ID,5,true);
DrawText(ID,'Your team got a new weapon!',180,White,0.06,160,200);
end;
3: begin
SetWeaponActive(ID,7,true);
DrawText(ID,'Your team got a new weapon!',180,White,0.06,160,200);
end;
end;
end;
Procedure OnPlayerKill(Killer, Victim: Byte; Weapon: String);
begin
// MapChange + additional weapons
case AlphaScore of
AlphaScore > (WepGap - 1): begin
if W1 then begin
W1 := false;
WepTemp := 1;
AllowWeapon();
end;
end;
Alphascore > (MapGap - 1): begin
if MapChange then begin
KickBots();
Command('/nextmap');
DrawText(0,'The Garmons have won the match! Congratulations!',3,White,0.15,160,200);
Wave := 1;
Msg := 1;
MapChange := false;
end;
end;
end;
case BravoScore of
BravoScore > (WepGap - 1): begin
if W2 then begin
W2 := false;
WepTemp := 2;
AllowWeapon();
end;
end;
Bravoscore > (MapGap - 1): begin
if MapChange then begin
KickBots();
Command('/nextmap');
DrawText(0,'The Verrights have won the match! Congratulations!',3,White,0.15,160,200);
Wave := 1;
Msg := 1;
MapChange := false;
end;
end;
end;
case CharlieScore of
CharlieScore > (WepGap - 1): begin
if W3 then begin
W3 := false;
WepTemp := 3;
AllowWeapon();
end;
end;
CharlieScore > (MapGap - 1): begin
if MapChange then begin
KickBots();
Command('/nextmap');
DrawText(0,'The Magi have won the match! Congratulations!',3,White,0.15,160,200);
Wave := 1;
Msg := 1;
MapChange := false;
end;
end;
end;
if DeltaScore <> 0 then
SetScore(4,0);
end;
-
function GetTeamKills(Team: byte): integer;
var i: byte;
begin
result := 0;
for i := 1 to 32 do if getplayerstat(i,'active') then if getplayerstat(i,'team') = team then result := result + getplayerstat(i,'kills');
end;
Crude but it should work, remember, the kills tallied for a player doesnt increase until after the onplayerkill() procedure exits, so you will need to add 1 to the result of the function above.
-
@hacktank: getplayerstat(i,'active') = true
-
@hacktank: getplayerstat(i,'active') = true
Why would you compare a True boolean to = True again ?
-
Because you need to compare them when using GetPlayerStat afaik.
Thanks, I already changed my script but didn't test it yet.
-
You don't afaik, works without it.
-
You don't afaik, works without it.
Since when? I thought it's bugging ;/
-
I'll test it, as an almost scientist I can't leave stuff that way.
edit: tk is right, there's no need for = true. Someone needs to be burnt in my opinion.
-
Someone needs to be burnt in my opinion.
@hacktank: getplayerstat(i,'active') = true
Have fun burning >;D
Anyway, I want to see what code you used to test it ;P
-
I'll test it, as an almost scientist I can't leave stuff that way.
edit: tk is right, there's no need for = true. Someone needs to be burnt in my opinion.
it starts throwing random errors after some time on some systems if you dont do it with "= true".
Spkka or sai´ke posted about this some years ago i think. NSC did too (more recently) - said it was because getplayerstat returns a variant, not a boolean, so it might act weird sometimes. That's a pascal/delphi "feature" apparently
-
NEVER, NEVER USE = true OR = false AGAIN EXCEPT FOR GetPlayerStat() STUFF.
Its more appropriate to say whenever dealing with a variant, which includes GetPlayerStat, but necessarily only that.
-
I removed Drain and added Vanish instead. Nextmap will be called when TimeLeft is under a certain amount. You get the new weapons after an amount of time either.
How can I check a text for certain characters?
-
I removed Drain and added Vanish instead. Nextmap will be called when TimeLeft is under a certain amount. You get the new weapons after an amount of time either.
How can I check a text for certain characters?
You mean this?
http://www.enesce.com/help/html/Functions/ContainsString.html
It cheecks on Haystack for Needle. Returns True or False if Matched/Not matched.
-
I want to change one value in an index of an array in a record and tried this (weapon is an array of booleans):
Player[ID].Weapon[ID2] := true;
But I get this error:
13:15:13 - Zombie MADNESS -> [Error] (219:25): Semicolon (';') expected
Line 218 is the line I've pasted here, char 25 is the dot after [ID]
-
This line is correct, the error must be somewhere else.
-
This is the whole procedure the line was taken from: (by the way: this happens everywhere where I try to access a value via Player[ID].Weapon[Index] ... same error, too)
// Buys a specified item
Procedure Buy(ID:Byte; Money,Item:Integer);
begin
if Item > 0 then begin
if Item < 16 then begin
if Money >= Price[Item] then begin
Player[ID].Money := Player[ID].Money - Price[Item];
case Item of
1,2,3,4,5,6,7,8,9,10: begin
ForceWeapon(ID,Item,GetPlayerStat(ID,'Primary'),0);
SetWeaponActive(ID,Item,true);
Player[ID].Weapon[Item] := true;
end;
11: DoDamage(ID,GetPlayerStat(ID,'Health') - 150);
12: GiveBonus(ID,4);
13: GiveBonus(ID,1);
14: GiveBonus(ID,2);
15: if GetPlayerStat(ID,'Ground') = true then begin
Player[ID].Turret := SpawnObject(GetPlayerStat(ID,'X'),GetPlayerStat(ID,'Y'),Item);
WriteConsole(ID,'You can move your turret by !moveturret', White);
end else WriteConsole(ID,'You must be standing on the ground to buy a turret.', Red);
16: if not Player[ID].Zombie then begin
Player[ID].Lives := Player[ID].Lives + 1;
WriteConsole(ID,'You feel stronger..', Orange);
end else WriteConsole(ID,'You are already a zombie.', Red);
17: if Player[ID].Zombie then begin
Player[ID].Zombie := false;
SetTeam(ID,1);
WriteConsole(ID,'You feel.. good! You just raised from the dead!', Orange);
end else WriteConsole(ID,'You are not infected.', Red);
end;
end else WriteConsole(ID,'You don''t have enough money.', Red);
end else WriteConsole(ID,'Invalid item ID.', Red);
end else WriteConsole(ID,'Invalid item ID.', Red);
end;
-
I dont watch this topic alot but what will be the full script ?
zombie survival ?
-
Post the var/type.
-
@mich: It'll be a remix of the good'ol (!KY) ZombieSurvival, the best zombie server ever imo
@piepie:
Type Stats = Record
Zombie,Weapon:Boolean;
Money,Turret,Lives:Integer;
Klasse: Byte; // 0: human 1: zombie 2: gunner 3: knifer 4: tank
end;
var
Player: Array[1..32] of Stats;
-
And where's the weapon array? :@
-
@mich: It'll be a remix of the good'ol (!KY) ZombieSurvival, the best zombie server ever imo
So i suport you for that !
and if you want a host located in canadas just ask !
-
Wrong script :3
-
Pfffffffft... seriously: /buy brains
-
Lmfao..
Should be:
Type Stats = Record
Zombie: Boolean;
Money, Turret, Lives: Integer;
Weapon: Array[0..16] of Boolean;
end;
Var
Player: Array[1..32] of Stats;
//In use:
Player[ID].Weapon[10] := True; //Should enable Minigun
Player[ID].Weapon[14] := False; //Disables Combat Knife
Player[ID].Weapon[16] := True; //Enables LAW, and there it goes.
//If you wanna use Stationarys too, go "Weapon: Array[0..17] of Boolean;".. 17 would be Stat.
//Good luck :)
//Hope I've helped :]
-
It was so basic that I didn't see it.. thanks guys (excluding Swompie >:( )
-
Haha, no problem.
I'm using that same trick on my current Script, so.. Feel free to ask me :)
-
It was so basic that I didn't see it.. thanks guys (excluding Swompie >:( )
You want me to say *RAWR* :D
-
Yeah I missed that freaking nice *RAWR* :P
-
Are your script finished ?
if yes , a server run it ?
-
As soon as it's ready I'll announce it here (I will host it)
-
Ok good :D
Where the server will be located ?
-
In Germany
EDIT: I wrote a mine script that should work but I'm getting this strange error:
10-05-30 03:36:16 [*] [Error] Test(Mine) -> (OnPlayerSpeak): Could not call proc
Here is the code:
const
White = $FFFFFF;
Orange = $FF7F24;
Red = $EE3B3B;
MineDuration = 180; // Time in seconds the mine lasts
MaxMines = 5; // Maximum amount of mines / map
MineRange = 45; // Range of mines (14 units = 1 meter)
MineM79 = 1; // MineXYZ increases the created bullets exponentially (MineM79 > MineGren > MineClux)
MineGren = 2;
MineClux = 3;
Type MineStats = Record
X,Y:Single;
Time:Integer;
end;
Type GeneralStats = Record
MineStat: Array of MineStats;
end;
var
Mine: Array[1..32] of GeneralStats;
NumMines: Byte;
Procedure DetonateMine(ID,Enemy:Byte; X,Y:Single);
var i,ii,iii:Byte;
R1,R2:Integer;
begin
for i := 1 to MineM79 do begin
R1 := Round(Random(-200,201) / 150);
R2 := Round(Random(100,326) / 150);
CreateBullet(X,Y,R1,R2,100,4,ID);
for ii := 1 to MineGren do begin
R1 := Round(Random(-250,251) / 125);
R2 := Round(Random(100,381) / 125);
CreateBullet(X,Y,R1,R2,100,2,ID);
for iii := 1 to MineClux do begin
R1 := Round(Random(-350,351) / 115);
R2 := Round(Random(100,501) / 115);
CreateBullet(X,Y,R1,R2,100,10,ID);
end;
end;
end;
WriteConsole(Enemy,'You stepped into a claymore.', Red);
WriteConsole(ID,IDToName(Enemy) + ' has stepped on one of your mines.', Orange);
NumMines := NumMines - 1;
end;
Procedure CallMines();
var i,ii,iii,All:Byte;
Dist:Single;
begin
for i := 1 to 32 do
if GetPlayerStat(i,'Active') = true then begin
All := GetArrayLength(Mine[i].MineStat);
for ii := 1 to All do begin
for iii := 1 to 32 do
if GetPlayerStat(iii,'Active') = true then
if GetPlayerStat(iii,'Alive') = true then
if (GetPlayerStat(iii,'Team') <> GetPlayerStat(i,'Team')) OR (GetPlayerStat(i,'Team') = 0) then begin
Dist := Distance(Mine[i].MineStat[ii].X,Mine[i].MineStat[ii].Y,GetPlayerStat(iii,'X'),GetPlayerStat(iii,'Y'));
if Dist <= MineRange then
DetonateMine(i,iii,Mine[i].Minestat[ii].X,Mine[i].MineStat[ii].Y);
end;
if Mine[i].MineStat[ii].Time <> - 1 then begin
Mine[i].MineStat[ii].Time := Mine[i].MineStat[ii].Time - 1;
CreateBullet(Mine[i].MineStat[ii].X,Mine[i].MineStat[ii].Y,0,0,0,7,i);
if Mine[i].MineStat[ii].Time = 0 then begin
WriteConsole(i,'One of your mines exceeds it''s duration and blows up.', Orange);
DetonateMine(i,iii,Mine[i].MineStat[ii].X,Mine[i].MineStat[ii].Y);
Mine[i].MineStat[ii].Time := - 1;
end;
end;
end;
end;
end;
Procedure PlaceMine(ID:Byte);
var ArrLength:Byte;
begin
if NumMines < MaxMines then begin
if GetPlayerStat(ID,'Alive') = true then begin
if GetPlayerStat(ID,'Ground') = true then begin
ArrLength := GetArrayLength(Mine[ID].MineStat);
SetArrayLength(Mine,ArrLength + 1);
Mine[ID].MineStat[ArrLength].X := GetPlayerStat(ID,'X');
Mine[ID].MineStat[ArrLength].Y := GetPlayerStat(ID,'Y');
Mine[ID].MineStat[ArrLength].Time := MineDuration;
NumMines := NumMines + 1;
WriteConsole(ID,'You have laid a mine successfully.', White);
end else WriteConsole(ID,'You must be standing on the ground.', Red);
end else WriteConsole(ID,'You must be alive to use skills.', Red);
end else WriteConsole(ID,'There are already ' + inttostr(MaxMines) + ' mines on the map.', Red);
end;
Procedure DestroyAllMines();
var i:Byte;
begin
for i := 1 to 32 do
if GetPlayerStat(i,'Active') = true then
SetArrayLength(Mine[i].MineStat,0);
end;
Procedure OnPlayerSpeak(ID:Byte; Text:String);
begin
case LowerCase(Text) of
'!mine','!test': PlaceMine(ID);
'!blowup','!blow': DestroyAllMines();
end;
end;
Procedure AppOnIdle(Ticks:Integer);
begin
CallMines();
end;
Procedure OnMapChange(NewMap:String);
begin
DestroyAllMines();
end;
-
dynamic array indexes start at 0, not 1. So if you have an empty array and add an element to it (do setarraylength(mines,1) ), there will be no mines[1], the only element will be mines[0]
edit: fixed a dumb early-in-the-morning mistake <.<
-
I have a little problem. I need to know a formula which changes my input to an opposite value. 0 would return 100, 1 returns 99, 10 returns 90, 25 returns 75, 50 returns 50 and so on ...
I don't want to create a huge list that would look very retarded :3
-
result := 100 - x;
fail
-
const
HK = 36;
Function OnPlayerDamage(Victim,Shooter:Byte; Damage:Integer):Integer;
var
Tmp:Integer;
begin
case GetPlayerStat(Shooter,'Primary') of
[...]
2: begin
Tmp := Round(Result * (100 - HK) / 100);
if Tmp + GetPlayerStat(Shooter,'Health') < 150 then begin
DoDamage(Shooter,-Tmp);
end else DoDamage(Shooter,GetPlayerStat(Shooter,'Health') - 150);
end;
[...]
end;
end;
Somehow this seems to cause the script I'm working on to crash after some time and I can't see any problems here..
EDIT: After I saw my post I acknowledged a possible cause why the forums' built-in syntax highlighting sometimes connects pieces of code. In this code I didn't use any tabs, could it be that?
-
how does it crash? And why are you so sure it's this exact piece of code that's doing it?
-
I took it out for a test and the server didn't crash. What's so weird is that there the server just shuts down. There is nothing special in the log ...
EDIT: Got a log:
10-06-06 17:52:13 [*] [Error] RandomWar -> (OnPlayerDamage): Access violation at address 00413D89 in module 'soldatserver.exe'. Read of address 015ABA8C
10-06-06 17:52:13 [*] [Error] RandomWar -> (OnPlayerDamage): Exception: Access violation at address 00413D89 in module 'soldatserver.exe'. Read of address 015ABA8C
10-06-06 17:52:13 [*] [Error] RandomWar -> (OnPlayerDamage): Exception: Access violation at address 00413D89 in module 'soldatserver.exe'. Read of address 015ABA8C
10-06-06 17:52:13 [*] [Error] RandomWar -> (OnPlayerDamage): Exception: Access violation at address 00413D89 in module 'soldatserver.exe'. Read of address 015ABA8C
10-06-06 17:52:13 [*] [Error] RandomWar -> (OnPlayerDamage): Exception: Access violation at address 00413D89 in module 'soldatserver.exe'. Read of address 015ABA8C
10-06-06 17:52:13 [*] [Error] RandomWar -> (OnPlayerDamage): Exception: Access violation at address 00413D89 in module 'soldatserver.exe'. Read of address 015ABA8C
10-06-06 17:52:13 [*] [Error] RandomWar -> (OnPlayerDamage): Exception: Access violation at address 00413D89 in module 'soldatserver.exe'. Read of address 015ABA8C
10-06-06 17:52:13 [*] [Error] RandomWar -> (OnPlayerDamage): Exception: Access violation at address 00413D89 in module 'soldatserver.exe'. Read of address 015ABA8C
10-06-06 17:52:13 [*] [Error] RandomWar -> (OnPlayerDamage): Exception: Access violation at address 00413D89 in module 'soldatserver.exe'. Read of address 015ABA8C
10-06-06 17:52:13 [*] [Error] RandomWar -> (OnPlayerDamage): Exception: Access violation at address 00413D89 in module 'soldatserver.exe'. Read of address 015ABA8C
10-06-06 17:52:13 [*] [Error] RandomWar -> (OnPlayerDamage): Exception: Access violation at address 00413D89 in module 'soldatserver.exe'. Read of address 015ABA8C
10-06-06 17:52:13 [*] Too many script errors! Shutting down server -> "RandomWar"
10-06-06 17:52:13 [*] [Error] RandomWar -> (OnPlayerDamage): Exception: Access violation at address 00413D89 in module 'soldatserver.exe'. Read of address 015ABA8C
10-06-06 17:52:13 [*] Too many script errors! Shutting down server -> "RandomWar"
Keeps repeating until it crashed. I just attached the script now.. involved weapons were Ruger and HK.
-
try changing line 88 to
if GetPlayerStat(Yah, 'Active') = true then begin
Edit: line 74 to
Player: Array [0..32] of Stats;
-
Dude, it's pretty much terrible to keep looking at those GetPieces().
Use "Var First, Second, Third" For "GetPieces(..0), 1 and 2".
@Dnmr, Array[0..32] ? Why would you use ID 0 ? Oo
-
@Dnmr, Array[0..32] ? Why would you use ID 0 ? Oo
ask the scriptcore why it like accessing the 0'th elements of arrays, i can only tell you it does that sometimes. And that leads to access violations all right (with different results on different systems)
Edit: ofc im not trying to say this will definitely solve the problem, i'm just saying i've had troubles with a similar case. And i haven't studied the code thoroughly, just went through it quickly, so someone else might find something more broken ::)
-
Might be a loop created by the dodamage inside the onplayerdamage().
The dodamage invokes a new onplayerdamage() which then does a new dodamage calling another onplayerdamage() and so on until it crashes
should try making a check so an onplayerdamage() started from the dodamage() can't do a dodamage.
-
@Squiddy: I changed the part for you
@Dnmr: Changed what you've mentioned
@Serial: Sounds reasonable, I'll give it a serious try :)
EDIT: I attached the updated script. Although I did what SK suggested the server crashes as soon as I hit an enemy with a HK bullet. If only the new Soldat version was out.. I'd be able to use M2 bullets via CreateBullet() to heal a specific amount of health :3
-
Tried it and it also crashed with me but when I commented the dodamage calls in onplayerdamage() there where no problems.
My guess is that the scriptcore doesn't like recursion, you could try storing the actions in an array or something and do them in AppOnIdle()
In 2.7.0 you can use the SetPlayerStat(ID,'health',value); function that doesn't call onplayerdamage() and so no recursion issues.
-
That worked out great, but I wonder how Avarax coded Vampirism (a skill in Hexer that does the same as the HK does in RandomWar) since you directly gain health..
How do I detect a kill by a grenade?
-
Pass the damage from onplayerdamage to dovamp():
procedure DoVamp(ID: byte; Damage: integer);
var heal: integer;
begin
heal := round((damage*0.4)+0.6);
dodamage(ID,-heal);
end;
How do I detect a kill by a grenade?
You dont, not until 1.5.1 anyway...
-
I tried that, HackTank, just the way you suggested to do it, but either I messed something up or it's not working properly because the server crashes again.
Script attached :3 (important lines: 277,492)
-
Are you using the beta server version? Does it crash on compile or during runtime?
I would think there would be extreme integer rounding because of integer math in your heal calculation, if there is (not sure if pascal does it this way, but in cpp it would be important) you need to replace the heal calculations with this:
Heal := Round(base * (100.0 - HK) / 100.0);
If you are running the beta version then the dodamage needs to be dodamage(target,target,-heal); If its runtime, it is due to an infanite loop, add an "if shooter <> victim" check before your case call.
-
How do I detect a kill by a grenade?
You dont, not until 1.5.1 anyway...
You can:
if Weapon = 'Grenage' then
WriteConsole(0, 'It was a grenade \o/', color);
-
@HackTank: Works after adding Victim <> Shooter, thank you :)
@Swompie: Didn't know that that's possible.. lol
EDIT:
Procedure OnPlayerKill(Killer,Victim:Byte; Weapon:String);
begin
if Killer <> Victim then
case LowerCase(Weapon) of
m79: if Random(1,101) <= M79 then Explosion(Victim,Killer);
minimi: if Random(1,101) <= Minimi then GiveRoundsBack(Killer,50);
minigun: if Random(1,101) <= Minigun then begin
GiveRoundsBack(Killer,MinigunR);
GiveBonus(Killer,5);
end;
flamer: if Random(1,101) <= Flamer then SetEnemiesOnFire(Killer);
knife: if Random(1,101) <= Knife then ForceNewKnife(Killer);
chainsaw: if Random(1,101) <= Chainsaw then begin
RestoreHealth(Killer,150);
GiveVest(Killer);
end;
law: if Random(1,101) <= LAW then ShootNextEnemy(Killer);
grenade: if Random(1,101) <= Grenade then
end;
end;
10-06-07 17:04:50 [*] RandomWar -> [Error] (488:3): Unknown identifier 'grenade'
-
(hint: weapon var is a string)
-
Referring to my own dumbness (thanks, Swomp): Kids out there please listen, don't do alcohol nor terrorcore :3
EDIT: I'm working on some kind of AntiCheat script (currently working against TeleHacks,MassFlag and .. too high ping). I use a .ini to make changes to the settings easier for users, but it fails badly. I put the .ini into the main server directory and always get the exception message that'll load the default settings either..
-
about HP leech - just make sure it doesnt activate if shooter = victim, otherwise you'll obviously end up in an endless loop (as SK already pointed out). There is no greater trick to it than that.
And thing about config files - they just bring more useless pain imo. Just declare the settings as consts in your script, it's as easy to modify as an .ini file. Unless, of course, you just want to practice handling files in such a widely used scripting language ._.
-
I'd like to use the .ini actually
-
Sorry for not being able to help you, DC, but I was quite busy. Anyways, seems you've got some amazing help anyway :D
For reading .INI files, use ReadINI(). There is a section for that on the Enesce manual.
It's good that you are able to interact with .INI files, buuut it should be easier, if not too many stuff, to just put that into the Constants, on the Script itself.
Although, if you have many stuff for many different stuff, then an .INI should be the best option, anyway.
Hope I've been helpfull.
Any other questions, feel free to ask us. Cya later :)
Edit.. I took a look at the Script.. Try this:
Var SettFile: String;
Begin
SettFile := 'YourDirectoryHere.ini';
if FileExists(SettFile) Then Begin
Try
StuffYouWantToLoad1 := StrToInt(ReadINI(SettFile,'Section','Max_Ping','');
StuffYouWantToLoad2 := StrToInt(ReadINI(SettFile,'Section','Squiddo','');
Except
WriteLn('Error ocurred while trying to load settings');
end;
end else WriteLn('File doesnt exists!');
end;
//Or something like that.
//I cant help much right now, 'coz I'm on my sister's laptop, and I don't got much time.. :P
//Later I can post an easier way to help you out.
-
Well, Squiddy, I know that and it looks almost exactly like your code, but there seems to be a problem with loading the stuff from the .ini and I really don't get why..
EDIT:
I used ';' at the end of each line in the settings.ini..
-
Do your zombie survival script is done ?
-
Still in work ;)
-
ok... so good working :P
i can't wait to play your server :D
-
I am working on enchantments for custom maps. You will be able to fire in a set interval between 2 spawn points or spawn objects. But I seem to be a master in getting the strangest and most exotic errors:
10-07-17 13:27:42 [*] [Error] MapEnchantments -> (AppOnIdle): Could not call proc
You can find the code here (http://darkcrusade.pastebin.com/iL42dcag). The procedure that causes the error is DeltaFireRegionTrigger().
-
Wasn't there a similar script already?
-
If you mean this (http://www.soldatcentral.com/index.php?page=script&f=39): I don't like it and it works in an other way than mine. While Spkka's script spawns a bullet with no velocity on a random spot between 2 Delta spawns mine fires bullets from one spawn to the other.
EDIT: VestSpawnWeaponTrigger() causes the same error and I don't know what to do..
EDIT2: Why isn't there a built-in GetTime() and GetDate() function? I need them for one of my scripts.
-
FormatDate...
-
Main answer:
Could not call proc happen always when you're trying to call function on a static array, which is dedicated for dynamic array.
For example, look for this:
var
MyStaticArray: array [0..anything] of byte;
MyDynamicArray: array of byte;
MyFunction();
var
i: byte;
begin
i := GetArrayLength(MyStaticArray); //this will cause error
i := GetArrayLength(MyDynamicArray); //this won't
SetArrayLength(MyStaticArray, anything+1); //this will cause error too
SetArrayLength(MyDynamicArray, anything+1); //this won't
end;
EDIT: VestSpawnWeaponTrigger() causes the same error and I don't know what to do..
Line 69: remove Len and replace it with VestWeaponSpawns. Should work w/o error
10-07-17 13:27:42 [*] [Error] MapEnchantments -> (AppOnIdle): Could not call proc
Line 43: remove Len and replace with DeltaFireRegions.
-
Sounds reasonable, thanks!