Official Soldat Forums

Server Talk => Scripting Discussions and Help => Topic started by: DarkCrusade on March 30, 2010, 09:36:25 am

Title: Question Thread
Post 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

Code: [Select]
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:
Code: [Select]
thenbegin
#2:
Code: [Select]
then begin
Title: Re: Question Thread
Post by: JFK on March 30, 2010, 10:52:45 am
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:
Code: [Select]
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:
Code: [Select]
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;
Title: Re: Question Thread
Post by: DarkCrusade on March 30, 2010, 11:22:31 am
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?

Code: [Select]
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;
Title: Re: Question Thread
Post by: Stuffy on March 30, 2010, 11:55:47 am
IntToStr in Integer To String, because you execute a command and thats a string, but your i-variable is an integer.
Title: Re: Question Thread
Post by: Silnikos on March 30, 2010, 03:10:28 pm
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.
Title: Re: Question Thread
Post by: DarkCrusade on March 30, 2010, 03:53:48 pm
I already do that, but still some questions come up. Is the line comment right?
Title: Re: Question Thread
Post by: JFK on March 30, 2010, 06:24:10 pm
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).
Title: Re: Question Thread
Post by: DarkCrusade on March 30, 2010, 08:24:18 pm
-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.
Title: Re: Question Thread
Post by: Hacktank on March 30, 2010, 08:34:52 pm
Permutations:
shutdown
disable
recompile
Title: Re: Question Thread
Post by: DarkCrusade on March 30, 2010, 08:44:00 pm
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 ...

Code: [Select]
procedure OnFlagScore (ID, TeamFlag: byte )
begin
    SetPlayerStat(ID, 'health', GetPlayerStat(ID, 'health') = 300);         
end;
Title: Re: Question Thread
Post by: chutem on March 30, 2010, 10:04:54 pm
Quote
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.
Title: Re: Question Thread
Post by: Gizd on March 30, 2010, 11:20:06 pm
Max HP is 200.
Title: Re: Question Thread
Post by: Hacktank on March 30, 2010, 11:51:40 pm
You need to scale the damage done using thier desired max health. Ill post an example onplayerdamage tomarrow if you want.
Title: Re: Question Thread
Post by: DarkCrusade on March 31, 2010, 02:32:01 am
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.
Title: Re: Question Thread
Post by: ShadowDancer on March 31, 2010, 02:44:29 am
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:
Code: [Select]
Damage := (Damage * ((100 * Hp) div MaxHp)) div 100; //may not works, written on fastFirst way is better(IMO).
Title: Re: Question Thread
Post by: Mercury92 on March 31, 2010, 03:48:35 am
Permutations:
shutdown
disable
recompile
recompile doesn't work for me, never seen it recompiling.
Title: Re: Question Thread
Post by: Swompie on March 31, 2010, 05:04:34 am
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:
Code: [Select]
DoDamage(ID, -200); //Heals them up to 200HP, w/e health they had before, if they're aliveNote: 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.
Title: Re: Question Thread
Post by: dnmr on March 31, 2010, 06:39:36 am
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
Title: Re: Question Thread
Post by: mich1103 on March 31, 2010, 02:55:58 pm
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 ...
Title: Re: Question Thread
Post by: Gizd on March 31, 2010, 03:05:18 pm
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?
Title: Re: Question Thread
Post by: Hacktank on March 31, 2010, 11:48:12 pm
Code: [Select]
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;
Title: Re: Question Thread
Post by: DarkCrusade on April 03, 2010, 03:26:00 pm
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.

Code: [Select]
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 ...
Title: Re: Question Thread
Post by: JFK on April 03, 2010, 07:36:07 pm
You only need ; to separate the arguments of a function, the last one is not needed.
In other words remove ; after Damage: Integer
Title: Re: Question Thread
Post by: DarkCrusade on April 03, 2010, 09:14:37 pm
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).

Code: [Select]
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;
Title: Re: Question Thread
Post by: croat1gamer on April 03, 2010, 09:20:11 pm
Did you specify the desiredmaxhealth before the first begin as a const?

Something like this:
Code: [Select]
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;
Title: Re: Question Thread
Post by: DarkCrusade on April 03, 2010, 10:41:38 pm
Hell my script looked exactly like yours, croat, I just forgot I need to declare variables via "const" ... Thanks for reminding me.

EDIT:

Code: [Select]
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).

Code: [Select]
// 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.







Title: Re: Question Thread
Post by: tk on April 04, 2010, 02:13:32 am
Code: [Select]
procedure OnAdminMessage(IP, Msg: String);
begin
  if Copy(Msg, 1, 4)='/say' then
    WriteConsole(0, '#################', $FFFF00);
end;

Code: [Select]
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
Title: Re: Question Thread
Post by: chutem on April 04, 2010, 02:24:27 am
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)
Quote
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  :|
Title: Re: Question Thread
Post by: DarkCrusade on April 04, 2010, 02:43:03 am
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?
Title: Re: Question Thread
Post by: tk on April 04, 2010, 02:49:21 am
no, in pascal it's <>

BooleanResult := Value1 = Value2;
if they are equal, the result will be true.
Title: Re: Question Thread
Post by: DarkCrusade on April 04, 2010, 03:52:33 am
Code: [Select]
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 ...
Title: Re: Question Thread
Post by: Swompie on April 04, 2010, 04:39:04 am
OnFlagReturn and OnFlagDrop aren't supported by the current server version, use v265.

Code: (pascal) [Select]
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)
Code: (pascal) [Select]
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.
Title: Re: Question Thread
Post by: Gizd on April 04, 2010, 01:41:34 pm
Code: [Select]
WriteLn('Bool is ' + iif(Bool,'true','false') + '!');\o/
Title: Re: Question Thread
Post by: Swompie on April 04, 2010, 02:00:34 pm
Gizd Gizd Gizd!! I tried to explain him the ways he can check if a bool is true/false.
Anyway thats too one xD
Title: Re: Question Thread
Post by: chutem on April 04, 2010, 03:56:39 pm
You are messing up your operators.

In this line
Code: [Select]
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
Code: [Select]
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.
Title: Re: Question Thread
Post by: DarkCrusade on April 05, 2010, 01:13:30 am
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 ...

Code: [Select]
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'.

Title: Re: Question Thread
Post by: chutem on April 05, 2010, 01:29:10 am
Remove the 'then', it is confusing the compiler.
Are you trying to use the procedure as some kind of if statement?
Title: Re: Question Thread
Post by: DarkCrusade on April 05, 2010, 02:03:14 am
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
Title: Re: Question Thread
Post by: tk on April 05, 2010, 02:34:27 am
http://enesce.com/help/index.html?Functions/WriteConsole.html
procedure WriteConsole(ID: Byte; Text: string; Colour: Longint)
Title: Re: Question Thread
Post by: DarkCrusade on April 05, 2010, 03:12:43 am
So I tried

Code: [Select]
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; 

Code: [Select]
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 ...
Title: Re: Question Thread
Post by: dnmr on April 05, 2010, 03:18:37 am
COMMA IN BETWEEN PARAMETERS, NOT A SEMICOLON
Title: Re: Question Thread
Post by: Gizd on April 05, 2010, 03:52:52 am
Code: [Select]
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?
Title: Re: Question Thread
Post by: DarkCrusade on April 05, 2010, 04:43:54 am
My logs work again. Right now ...

Code: [Select]
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?
Title: Re: Question Thread
Post by: ShadowDancer on April 05, 2010, 05:13:33 am
Why you have function declaration in another function?
Title: Re: Question Thread
Post by: Swompie on April 05, 2010, 05:20:09 am
Code: [Select]
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.
Code: [Select]
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;
Title: Re: Question Thread
Post by: DarkCrusade on April 05, 2010, 06:04:48 am
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.
Title: Re: Question Thread
Post by: Swompie on April 05, 2010, 07:57:56 am
[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:
Code: [Select]
// 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.
Title: Re: Question Thread
Post by: DarkCrusade on April 05, 2010, 01:21:58 pm
So I got some more time and got the first part working.

Code: [Select]
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)

Code: [Select]
procedure OnPlayerSpeak(ID:Byte;Text:String);
begin
  if(Text='!help')
     then begin
          WriteConsole('/say  ', $FFFFFFF);
          WriteConsole('/say  ', $FFFFFFF);
     end;
Title: Re: Question Thread
Post by: mich1103 on April 05, 2010, 01:36:22 pm
only need to do
Code: [Select]
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 !
Title: Re: Question Thread
Post by: Swompie on April 05, 2010, 01:37:31 pm
Code: [Select]
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)
Code: [Select]
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;
Code: [Select]
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.
Title: Re: Question Thread
Post by: mich1103 on April 05, 2010, 01:38:51 pm
And that
Code: [Select]
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;
Title: Re: Question Thread
Post by: DarkCrusade on April 05, 2010, 02:11:59 pm
Damnit ...

Code: [Select]
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 ...

Code: [Select]
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?
Title: Re: Question Thread
Post by: mich1103 on April 05, 2010, 02:26:34 pm
this is not good
Code: [Select]
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
Code: [Select]
Command('/say TEXT HERE');If you dont want the *SERVER* in front of your message do
Code: [Select]
WriteConsole(ID,'TEXT HERE',$EE81FAA1);i hope that will help u :P
Title: Re: Question Thread
Post by: Gizd on April 05, 2010, 02:57:22 pm
Code: [Select]
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
Title: Re: Question Thread
Post by: dnmr on April 05, 2010, 03:22:08 pm
Am I really that dumb?
im afraid so, if you cant count to TWO :/
Title: Re: Question Thread
Post by: DarkCrusade on April 06, 2010, 01:36:39 am
Well, I already came to that conclusion. I just wasn´t sure :P Currently I am using ...

Code: [Select]
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.
Title: Re: Question Thread
Post by: Silnikos on April 06, 2010, 02:03:40 am
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:
Code: [Select]
(...)
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:

Code: [Select]
(...)
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.
Title: Re: Question Thread
Post by: DarkCrusade on April 09, 2010, 01:51:21 pm
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 ...

Code: (Pascal) [Select]
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
Title: Re: Question Thread
Post by: Swompie on April 09, 2010, 02:13:08 pm
wb DC.

Code: [Select]
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 ;)
Title: Re: Question Thread
Post by: DarkCrusade on April 09, 2010, 02:27:29 pm
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 ...

Code: [Select]
if Text='!Help' OR  Text='!help' then begin
[...]
end;

But ...

Code: [Select]
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...
Title: Re: Question Thread
Post by: Gizd on April 09, 2010, 02:49:26 pm
You need ( ) because it does it this way atm:
1. Text = '!help' => boolean1
2. boolean1 OR Text => boolean or string operation => failure
Title: Re: Question Thread
Post by: Swompie on April 09, 2010, 02:49:36 pm
The brackets weren't wrong.
Code: [Select]
if Text = '!help' then begin
if (Text = '!help') then begin
Both of these ways work.



Example for or, Here you need brackets!
Code: [Select]
if (Text = '!help') or (Text = '!Help') then beginThat's how you go, however heres a better solution:
Code: [Select]
if LowerCase(Text) = '!help' then beginNo matter how a player wrote !help, will it be !HeLp or !helP, it will be always executed.
Title: Re: Question Thread
Post by: dnmr on April 09, 2010, 02:53:05 pm
you were missing begin and end; in the last post, that's what PIE fixed
Title: Re: Question Thread
Post by: DarkCrusade on April 09, 2010, 03:33:01 pm
type:
Code: [Select]
// 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.
Title: Re: Question Thread
Post by: Gizd on April 09, 2010, 03:38:23 pm
You don't need types as a beginner...
Title: Re: Question Thread
Post by: DarkCrusade on April 10, 2010, 02:39:39 am
That didn´t help me much, Gizd.

I want to have different classes for different people.
Title: Re: Question Thread
Post by: chutem on April 10, 2010, 03:41:38 am
Code: (pascal) [Select]
// 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
Code: (pascal) [Select]
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
Code: (pascal) [Select]
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
Code: (pascal) [Select]
Player[12].Level
Player[3].LoggedIn
Player[7].Skills
Title: Re: Question Thread
Post by: DarkCrusade on April 10, 2010, 04:26:47 am
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:

Code: [Select]
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 ...

Code: [Select]
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;           
Title: Re: Question Thread
Post by: chutem on April 10, 2010, 04:37:31 am
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).
Title: Re: Question Thread
Post by: DarkCrusade on April 10, 2010, 06:34:29 am
Okay I changed Klasse from byte to string, but now it returns me this:

Code: [Select]
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
Title: Re: Question Thread
Post by: EnEsCe on April 10, 2010, 06:44:05 am
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');"
Title: Re: Question Thread
Post by: Swompie on April 10, 2010, 08:01:05 am
Upload your script again, then I'm gonna help you abit :]
Title: Re: Question Thread
Post by: DarkCrusade on April 10, 2010, 09:23:58 am
Reupload. Changed the things EnEsCe mentioned but not more yet

The error changed a bit. Now it´s ...

Code: [Select]
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...
Title: Re: Question Thread
Post by: mich1103 on April 10, 2010, 09:34:37 am
What mean that ?
if Timer > 0 then Timer := Timer -1
Title: Re: Question Thread
Post by: Swompie on April 10, 2010, 09:55:06 am
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 (;)



Code: [Select]
procedure SetKlasse(ID, Klasse: String);
begin
Player[ID].Klasse := Klasse;
end;

Code: [Select]
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)
Title: Re: Question Thread
Post by: squiddy on April 10, 2010, 09:58:54 am
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 :]

Code: [Select]
//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.
Title: Re: Question Thread
Post by: DarkCrusade on April 10, 2010, 10:41:02 am
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!
Title: Re: Question Thread
Post by: squiddy on April 10, 2010, 10:43:03 am
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.
Title: Re: Question Thread
Post by: DarkCrusade on April 10, 2010, 10:54:45 am
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.
Title: Re: Question Thread
Post by: squiddy on April 10, 2010, 11:10:05 am
About the Damage stuff.. Add this to the Script:

Code: [Select]
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:

Code: [Select]
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:

Code: [Select]
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..
Title: Re: Question Thread
Post by: DarkCrusade on April 10, 2010, 11:44:54 am
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?
Title: Re: Question Thread
Post by: squiddy on April 10, 2010, 11:54:05 am
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..

Code: [Select]
[...] 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.
Title: Re: Question Thread
Post by: DarkCrusade on April 10, 2010, 12:30:01 pm
Works great. Awesome that there is this Raycast function since I will add a Ninja class. Right now the DoDamage part looks like this:

Code: [Select]
// 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:

Code: [Select]
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
Title: Re: Question Thread
Post by: Swompie on April 10, 2010, 12:32:50 pm
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?
Title: Re: Question Thread
Post by: DarkCrusade on April 10, 2010, 12:42:35 pm
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.
Title: Re: Question Thread
Post by: Swompie on April 10, 2010, 02:19:09 pm
Well, with DoDamageBy you can specify which person deals damage to someone, with DoDamage it's just the player itself whos damaging hismelf afaik.
Title: Re: Question Thread
Post by: DarkCrusade on April 10, 2010, 02:37:56 pm
Code: [Select]
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 ...

Code: [Select]
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;
Title: Re: Question Thread
Post by: Gizd on April 10, 2010, 03:10:47 pm
Code: [Select]
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:
Code: [Select]
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...
Title: Re: Question Thread
Post by: DarkCrusade on April 10, 2010, 05:01:42 pm
Well well, Gizd. I put the variables to the beginning and got some errors because of Raycast. Raycast didn´t change.
Title: Re: Question Thread
Post by: chutem on April 10, 2010, 08:15:33 pm
Why are you using rayCast to find the closest player?...
Title: Re: Question Thread
Post by: SpiltCoffee on April 10, 2010, 08:26:50 pm
Try this with that procedure that Gizd mentioned.

Code: (pascal) [Select]
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;
Title: Re: Question Thread
Post by: DarkCrusade on April 11, 2010, 01:55:16 am
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.

Code: [Select]
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.
Title: Re: Question Thread
Post by: Swompie on April 11, 2010, 03:52:39 am
Code: [Select]
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 :|
Title: Re: Question Thread
Post by: Gizd on April 11, 2010, 04:02:53 am
*CAPSLOCK ON*
PROTIP: LEARN TO DO PROPER INDENTATIONS OR YOU WON'T FIND MISSING END'S / BEGIN'S
Title: Re: Question Thread
Post by: DarkCrusade on April 11, 2010, 04:06:40 am
@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.
Title: Re: Question Thread
Post by: Swompie on April 11, 2010, 05:52:49 am
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.
Title: Re: Question Thread
Post by: DarkCrusade on April 11, 2010, 07:02:57 am
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:

Code: [Select]
var  
  Klasse: array[1..32] of string;
  SmnPower: array[1..32] of byte;

Procedure OnPlayerSpeak for sure ;)

Code: [Select]

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.

Code: [Select]
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:

Code: [Select]
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.
Title: Re: Question Thread
Post by: Swompie on April 11, 2010, 07:33:01 am
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:
Code: [Select]
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.

Code: [Select]
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]
Title: Re: Question Thread
Post by: DarkCrusade on April 11, 2010, 08:36:41 am
This returns me the error "Type Mismatch" ...

Code: [Select]
if  smnPower > 10 then
    SmnPower := 10;

... too bad :) Thanks for your advice ;)
Title: Re: Question Thread
Post by: Swompie on April 11, 2010, 09:04:28 am
Hint: Look at the variables you declared at the beginning, then this should be solved :]
Title: Re: Question Thread
Post by: DarkCrusade on April 11, 2010, 09:14:15 am
How could I forget that ;D Anyway, still there is a bug:

Code: [Select]
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:

Code: [Select]
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...
Title: Re: Question Thread
Post by: Swompie on April 11, 2010, 09:20:26 am
You've got too much ends in OnPlayerKill :E (2 too much if I counted right)

Btw.
Quote from: Swompie
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:
Code: [Select]
begin
|   begin
|   |   begin
|   |   end;
|   end;
end;
Got it what I mean? :p
Title: Re: Question Thread
Post by: mich1103 on April 11, 2010, 09:21:24 am
Hmmm im not sure about what i will right but i think it should be like that


Code: [Select]
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            
Title: Re: Question Thread
Post by: Swompie on April 11, 2010, 09:27:57 am
For each begin you need an end;
For each end; you need a begin
Title: Re: Question Thread
Post by: mich1103 on April 11, 2010, 09:28:43 am
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
Title: Re: Question Thread
Post by: DarkCrusade on April 11, 2010, 09:33:18 am
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 ;)
Title: Re: Question Thread
Post by: Swompie on April 11, 2010, 09:57:39 am
Giev code then I add how to make that :E
Title: Re: Question Thread
Post by: DarkCrusade on April 11, 2010, 10:32:39 am
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?
Title: Re: Question Thread
Post by: Gizd on April 11, 2010, 11:28:57 am
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: ............
Title: Re: Question Thread
Post by: squiddy on April 11, 2010, 11:33:18 am
[...]
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.

Code: [Select]
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.
Title: Re: Question Thread
Post by: DarkCrusade on April 11, 2010, 11:34:11 am
Who cares about indentations if it´s only like that at the forum. Read my script and see my almighty indentations, Gizd ...

Yay, rescue!
Title: Re: Question Thread
Post by: Gizd on April 11, 2010, 11:35:43 am
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 :<)
Title: Re: Question Thread
Post by: Swompie on April 11, 2010, 11:36:50 am
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.
Title: Re: Question Thread
Post by: DarkCrusade on April 11, 2010, 11:37:43 am
I didn´t force you to post, did I :P Will your vengeance be that you stop posting here? *almosthappy* :)

Thanks, Swomp [pigtail]
Title: Re: Question Thread
Post by: squiddy on April 11, 2010, 11:41:44 am
Case you, DC, havent noticed, check out my last post, I edited it and posted the Bot stuff.
Title: Re: Question Thread
Post by: DarkCrusade on April 11, 2010, 01:13:35 pm
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 ...

Code: [Select]
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.
Title: Re: Question Thread
Post by: squiddy on April 11, 2010, 01:28:13 pm
You missed an 'End;' at the end of the AppOnIdle Procedure..

Try this, it should work:

Code: [Select]
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;
Title: Re: Question Thread
Post by: DarkCrusade on April 11, 2010, 01:59:35 pm
This is weird. The script compiles but gets caught in an endless loop and kicks a player. Since there is no ... screen attached.
Title: Re: Question Thread
Post by: squiddy on April 11, 2010, 02:12:48 pm
You had no indentifer for DC, so it kept kicking players.

I hope this works.

Title: Re: Question Thread
Post by: DarkCrusade on April 11, 2010, 02:32:30 pm
Same problem.
Title: Re: Question Thread
Post by: squiddy on April 11, 2010, 03:19:58 pm
Try replacing this AppOnIdle(); then..

Code: [Select]
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.
Title: Re: Question Thread
Post by: DarkCrusade on April 12, 2010, 06:40:48 am
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

Code: [Select]
[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).
Title: Re: Question Thread
Post by: Swompie on April 12, 2010, 09:34:14 am
Weapon has to be Combat Knife  :P
You can disable bot chat in soldat.ini, it's on bottom of file.
Title: Re: Question Thread
Post by: DarkCrusade on April 12, 2010, 09:42:58 am
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).
Title: Re: Question Thread
Post by: croat1gamer on April 12, 2010, 09:47:33 am
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.
Title: Re: Question Thread
Post by: DarkCrusade on April 12, 2010, 10:11:11 am
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.
Title: Re: Question Thread
Post by: croat1gamer on April 12, 2010, 10:15:20 am
Code: [Select]
[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.
Title: Re: Question Thread
Post by: Swompie on April 12, 2010, 10:29:43 am
Bot which spawns with a knife and throws a knife:
Code: [Select]
Favourite_Weapon=Combat Knife
Secondary_Weapon=1
Title: Re: Question Thread
Post by: DarkCrusade on April 13, 2010, 12:20:43 pm
--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 ...

Code: [Select]
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 ;)
Title: Re: Question Thread
Post by: Swompie on April 13, 2010, 12:59:48 pm
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)
Title: Re: Question Thread
Post by: DarkCrusade on April 14, 2010, 08:19:20 am
What is the ID of the flamer? For my new class I need a ForceWeapon function ...

Code: [Select]
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;
Title: Re: Question Thread
Post by: squiddy on April 14, 2010, 08:32:57 am
Try this:

ForceWeapon(ID,11,0,0);

Flamer ID is 11.
Title: Re: Question Thread
Post by: DarkCrusade on April 14, 2010, 09:26:55 am
Thank you, where can I find the ID list?
Title: Re: Question Thread
Post by: Swompie on April 14, 2010, 09:41:05 am
In the core.pas (default) as consts.
Title: Re: Question Thread
Post by: DarkCrusade on April 14, 2010, 09:57:54 am
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 ...

Code: [Select]
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.

Code: [Select]
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;
Title: Re: Question Thread
Post by: Swompie on April 14, 2010, 09:59:47 am
Code: [Select]
if GetPlayerStat(DC, 'Primary') <> 11 then
Title: Re: Question Thread
Post by: Gizd on April 14, 2010, 11:56:37 am
Code: [Select]
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.
Title: Re: Question Thread
Post by: DarkCrusade on April 14, 2010, 12:15:12 pm
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

Code: [Select]
// 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.

Code: [Select]
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...
Title: Re: Question Thread
Post by: JFK on April 14, 2010, 01:11:15 pm
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.

Code: [Select]
// 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?

Code: [Select]
       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.

Code: [Select]
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:
Code: [Select]
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 ;)
   
Title: Re: Question Thread
Post by: Swompie on April 14, 2010, 01:12:28 pm
Pfft, nvm JFK was faster :D

You need to use RGB(R, G, B);
For the timer you need a var.
To display it:
Code: [Select]
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);
Title: Re: Question Thread
Post by: squiddy on April 14, 2010, 01:43:34 pm
Swompie, all good, except you dont have to use "if (TimerVar < 6) And (TimerVar > 0)"..

Just go..

Code: [Select]
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
Title: Re: Question Thread
Post by: DarkCrusade on April 14, 2010, 02:22:30 pm
Never saw such an error before ...

Code: [Select]
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.

Code: [Select]
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;
Title: Re: Question Thread
Post by: Gizd on April 14, 2010, 02:28:07 pm
Do you have any brain?
Code: [Select]
EngineerTimer = STARTTIME;
Title: Re: Question Thread
Post by: DarkCrusade on April 14, 2010, 02:36:14 pm
The fuck now I have really no idea. The specific line includes "end;" and nothing else. What is this caused by?

Code: [Select]
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.
Title: Re: Question Thread
Post by: Gizd on April 14, 2010, 02:38:53 pm
Why don't you just paste line 233?
Title: Re: Question Thread
Post by: DarkCrusade on April 14, 2010, 02:40:20 pm
Code: [Select]
DrawText(DC,'Gun removed',120,Color,(255,255,255),5,50);
Title: Re: Question Thread
Post by: Gizd on April 14, 2010, 02:44:50 pm
See? Much better. What's that (255,255,255) meant to be?
Title: Re: Question Thread
Post by: DarkCrusade on April 14, 2010, 02:50:48 pm
I took it from here. (http://devs.soldat.pl/wiki/index.php?title=DrawText)
Title: Re: Question Thread
Post by: Gizd on April 14, 2010, 02:55:10 pm
Yours:
Code: [Select]
DrawText(0,'xxx',120,Color,(255,255,255),5,50);Wiki:
Code: [Select]
DrawText(0,'xxx',330,RGB(255,255,255),0.20,40,240);
Title: Re: Question Thread
Post by: DarkCrusade on April 14, 2010, 03:03:41 pm
One fixed, one new, but somewhere else:

Code: [Select]
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:

Code: [Select]
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...
Title: Re: Question Thread
Post by: Swompie on April 14, 2010, 03:05:03 pm
Swompie, all good, except you dont have to use "if (TimerVar < 6) And (TimerVar > 0)"..

Just go..

Code: [Select]
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 -> :=
Title: Re: Question Thread
Post by: Gizd on April 14, 2010, 03:05:59 pm
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...).
Title: Re: Question Thread
Post by: DarkCrusade on April 14, 2010, 03:07:48 pm
@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?
Title: Re: Question Thread
Post by: Gizd on April 14, 2010, 03:09:49 pm
Oh I see...
Code: [Select]
      GetPlayerStat(Killer,'Health');Please explain what is that meant to do.
Title: Re: Question Thread
Post by: DarkCrusade on April 14, 2010, 03:14:18 pm
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.
Title: Re: Question Thread
Post by: dnmr on April 14, 2010, 03:17:43 pm
@ 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
Title: Re: Question Thread
Post by: squiddy on April 14, 2010, 06:14:06 pm
@ 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".

Code: [Select]
WriteConsole(ID,MyInteger,$FFFFFF);
Would go wrong. You have to do:

Code: [Select]
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.
Title: Re: Question Thread
Post by: dnmr on April 14, 2010, 11:21:15 pm
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:
Code: (pascal) [Select]
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

Code: (pascal) [Select]
if 'Health' <> 0 = false then beginagain, 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.
Title: Re: Question Thread
Post by: DarkCrusade on April 15, 2010, 01:22:59 am
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:

Code: [Select]
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.
Title: Re: Question Thread
Post by: SpiltCoffee on April 15, 2010, 03:34:49 am
Code: (pascal) [Select]
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.
Title: Re: Question Thread
Post by: dnmr on April 15, 2010, 04:56:39 am
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
Title: Re: Question Thread
Post by: DarkCrusade on April 15, 2010, 07:42:34 am
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?
Title: Re: Question Thread
Post by: squiddy on April 15, 2010, 10:00:16 am
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
Title: Re: Question Thread
Post by: DarkCrusade on April 16, 2010, 04:28:06 am
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.

Code: [Select]
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;
Title: Re: Question Thread
Post by: mich1103 on April 16, 2010, 05:08:29 am
Can you send the whole script because i dont know where is the line 182:1
Title: Re: Question Thread
Post by: DarkCrusade on April 16, 2010, 05:38:32 am
I marked the line. I won´t upload the whole script until the next version is ready.
Title: Re: Question Thread
Post by: mich1103 on April 16, 2010, 05:39:59 am
Hmmmm which line get an error ?
Title: Re: Question Thread
Post by: Swompie on April 16, 2010, 06:39:26 am
Out of my expierence you may forgot a begin/end above OnPlayerDamage; Actually not 100% sure, but look if it is so :p
Title: Re: Question Thread
Post by: Gizd on April 16, 2010, 08:56:34 am
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.
Title: Re: Question Thread
Post by: Swompie on April 16, 2010, 09:07:16 am
Code: [Select]
   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.
Title: Re: Question Thread
Post by: DorkeyDear on April 16, 2010, 10:12:52 am
@Swompie: In addition, for note, I think (not 100% certain) next scripting core, max value is included in the Random function.
Title: Re: Question Thread
Post by: DarkCrusade on April 16, 2010, 10:32:30 am
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 :)
Title: Re: Question Thread
Post by: squiddy on April 16, 2010, 12:21:17 pm
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.
Title: Re: Question Thread
Post by: DarkCrusade on April 16, 2010, 12:25:26 pm
I´m arleady using that stuff and fixed all bugs, thanks :) (and I understand the thing about Random ;) )
Title: Re: Question Thread
Post by: squiddy on April 16, 2010, 12:45:06 pm
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
Title: Re: Question Thread
Post by: DarkCrusade on April 17, 2010, 11:55:20 am
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?
Title: Re: Question Thread
Post by: dnmr on April 17, 2010, 12:28:53 pm
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
Title: Re: Question Thread
Post by: DarkCrusade on April 17, 2010, 12:49:49 pm
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)
Title: Re: Question Thread
Post by: squiddy on April 17, 2010, 02:31:42 pm
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 :)
Title: Re: Question Thread
Post by: DarkCrusade on April 17, 2010, 02:37:04 pm
Thank you, man :)
Title: Re: Question Thread
Post by: Gizd on April 17, 2010, 02:47:24 pm
- PunishBot (kicks spammers and bans them for x minutes (nearly finished)
You know there's a built-in anti-flood?
Title: Re: Question Thread
Post by: DarkCrusade on April 18, 2010, 08:13:40 am
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% ...

Code: [Select]
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)
Title: Re: Question Thread
Post by: dnmr on April 18, 2010, 08:45:46 am
http://forums.soldat.pl/index.php?topic=37855.msg462039#msg462039
Title: Re: Question Thread
Post by: DarkCrusade on April 18, 2010, 09:35:44 am
Next question: Why do I blame myself? ;D
Title: Re: Question Thread
Post by: dnmr on April 18, 2010, 11:32:38 am
Next question: Why do I blame myself? ;D
because you should
Title: Re: Question Thread
Post by: squiddy on April 18, 2010, 12:09:41 pm
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 :]
Title: Re: Question Thread
Post by: Runny on April 18, 2010, 12:13:26 pm
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?
Title: Re: Question Thread
Post by: dnmr on April 18, 2010, 12:19:25 pm
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
Title: Re: Question Thread
Post by: Runny on April 18, 2010, 12:24:13 pm
Thanks!
Title: Re: Question Thread
Post by: DarkCrusade on April 19, 2010, 11:28:16 am
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).
Title: Re: Question Thread
Post by: Swompie on April 19, 2010, 12:18:26 pm
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
Title: Re: Question Thread
Post by: DarkCrusade on April 21, 2010, 08:55:34 am
Compiles, but there is an OutOfRange error OnMapChange and I don't know what could have caused it, any thoughts?

Code: [Select]
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;


Title: Re: Question Thread
Post by: Swompie on April 21, 2010, 09:33:45 am
Out of range -> You are trying to access an index of an array which doesn't exists.
Title: Re: Question Thread
Post by: croat1gamer on April 22, 2010, 06:57:12 am
PlaID has to be an array of integers or sth like that. Not just an integer.
You didnt define Warning and Spamming.
Title: Re: Question Thread
Post by: Swompie on April 22, 2010, 07:13:58 am
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.
Title: Re: Question Thread
Post by: squiddy on April 23, 2010, 09:40:59 pm
He just forgot to put an begin in the loop.

Not really, he just forgot to check is PlaID is on server.

Code: (pascal) [Select]
OnMapChange();
For PlaID := 1 To 32 Do if GetPlayerStat(PlaID,'Active') = True Then
{ Statements }
End;
Title: Re: Question Thread
Post by: DarkCrusade on May 02, 2010, 09:35:00 am
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:

Code: [Select]
var
  ShowDmg: Boolean;

Code: [Select]
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:

Code: [Select]
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.
Title: Re: Question Thread
Post by: squiddy on May 02, 2010, 09:59:02 am
Code: (pascal) [Select]
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:

Code: (pascal) [Select]
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
Title: Re: Question Thread
Post by: DarkCrusade on May 02, 2010, 10:15:43 am
@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..
Title: Re: Question Thread
Post by: Swompie on May 02, 2010, 10:21:00 am
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  ::)
Code: [Select]
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:
Code: [Select]
  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():
Code: [Select]
  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.
Title: Re: Question Thread
Post by: squiddy on May 02, 2010, 10:28:59 am
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.
Title: Re: Question Thread
Post by: DarkCrusade on May 02, 2010, 11:02:55 am
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?
Title: Re: Question Thread
Post by: squiddy on May 02, 2010, 11:19:03 am
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.
Title: Re: Question Thread
Post by: Swompie on May 02, 2010, 12:26:22 pm
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.
Title: Re: Question Thread
Post by: squiddy on May 02, 2010, 12:34:34 pm
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
Title: Re: Question Thread
Post by: DarkCrusade on May 03, 2010, 01:00:56 pm
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 ...

Code: [Select]
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;
Title: Re: Question Thread
Post by: Hacktank on May 03, 2010, 05:05:31 pm
Code: [Select]
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.
Title: Re: Question Thread
Post by: Gizd on May 04, 2010, 02:51:33 am
@hacktank: getplayerstat(i,'active') = true
Title: Re: Question Thread
Post by: squiddy on May 04, 2010, 04:38:39 am
@hacktank: getplayerstat(i,'active') = true

Why would you compare a True boolean to = True again ?
Title: Re: Question Thread
Post by: DarkCrusade on May 04, 2010, 05:43:07 am
Because you need to compare them when using GetPlayerStat afaik.

Thanks, I already changed my script but didn't test it yet.
Title: Re: Question Thread
Post by: tk on May 04, 2010, 06:46:38 am
You don't afaik, works without it.
Title: Re: Question Thread
Post by: Swompie on May 04, 2010, 08:52:08 am
You don't afaik, works without it.
Since when? I thought it's bugging ;/
Title: Re: Question Thread
Post by: Gizd on May 04, 2010, 10:15:23 am
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.
Title: Re: Question Thread
Post by: Swompie on May 04, 2010, 10:57:07 am
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
Title: Re: Question Thread
Post by: dnmr on May 04, 2010, 11:13:42 am
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
Title: Re: Question Thread
Post by: DorkeyDear on May 04, 2010, 01:16:55 pm
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.
Title: Re: Question Thread
Post by: DarkCrusade on May 13, 2010, 11:49:38 pm
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?
Title: Re: Question Thread
Post by: squiddy on May 14, 2010, 04:05:41 am
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.
Title: Re: Question Thread
Post by: DarkCrusade on May 29, 2010, 07:15:45 am
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 

Line 218 is the line I've pasted here, char 25 is the dot after [ID]
Title: Re: Question Thread
Post by: tk on May 29, 2010, 07:44:00 am
This line is correct, the error must be somewhere else.
Title: Re: Question Thread
Post by: DarkCrusade on May 29, 2010, 09:28:15 am
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)

Code: (pascal) [Select]
// 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;
Title: Re: Question Thread
Post by: mich1103 on May 29, 2010, 10:17:45 am
I dont watch this topic alot but what will be the full script ?
zombie survival ?
Title: Re: Question Thread
Post by: Swompie on May 29, 2010, 11:04:11 am
Post the var/type.
Title: Re: Question Thread
Post by: DarkCrusade on May 29, 2010, 11:43:55 am
@mich: It'll be a remix of the good'ol (!KY) ZombieSurvival, the best zombie server ever imo

@piepie:

Code: (pascal) [Select]
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;
Title: Re: Question Thread
Post by: Swompie on May 29, 2010, 12:06:14 pm
And where's the weapon array? :@
Title: Re: Question Thread
Post by: mich1103 on May 29, 2010, 12:09:49 pm
@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 !
Title: Re: Question Thread
Post by: DarkCrusade on May 29, 2010, 12:19:06 pm
Wrong script :3
Title: Re: Question Thread
Post by: Swompie on May 29, 2010, 12:27:23 pm
Pfffffffft... seriously: /buy brains
Title: Re: Question Thread
Post by: squiddy on May 29, 2010, 03:32:56 pm
Lmfao..

Should be:

Code: (pascal) [Select]
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 :]
Title: Re: Question Thread
Post by: DarkCrusade on May 29, 2010, 03:47:24 pm
It was so basic that I didn't see it.. thanks guys (excluding Swompie >:( )
Title: Re: Question Thread
Post by: squiddy on May 29, 2010, 03:48:43 pm
Haha, no problem.

I'm using that same trick on my current Script, so.. Feel free to ask me :)
Title: Re: Question Thread
Post by: Swompie on May 29, 2010, 04:37:27 pm
It was so basic that I didn't see it.. thanks guys (excluding Swompie >:( )
You want me to say *RAWR* :D
Title: Re: Question Thread
Post by: DarkCrusade on May 29, 2010, 04:42:15 pm
Yeah I missed that freaking nice *RAWR* :P
Title: Re: Question Thread
Post by: mich1103 on May 29, 2010, 05:44:03 pm
Are your script finished ?
if yes , a server run it ?
Title: Re: Question Thread
Post by: DarkCrusade on May 29, 2010, 06:26:02 pm
As soon as it's ready I'll announce it here (I will host it)
Title: Re: Question Thread
Post by: mich1103 on May 29, 2010, 08:30:49 pm
Ok good  :D
Where the server will be located ?
Title: Re: Question Thread
Post by: DarkCrusade on May 29, 2010, 08:33:02 pm
In Germany

EDIT: I wrote a mine script that should work but I'm getting this strange error:

Code: [Select]
10-05-30 03:36:16  [*] [Error] Test(Mine) -> (OnPlayerSpeak): Could not call proc
Here is the code:

Code: (pascal) [Select]
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;
Title: Re: Question Thread
Post by: dnmr on May 29, 2010, 11:45:50 pm
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 <.<
Title: Re: Question Thread
Post by: DarkCrusade on May 30, 2010, 07:46:57 am
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
Title: Re: Question Thread
Post by: tk on May 30, 2010, 07:49:29 am
result := 100 - x;
fail
Title: Re: Question Thread
Post by: DarkCrusade on June 06, 2010, 05:40:35 am
Code: (Pascal) [Select]
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?
Title: Re: Question Thread
Post by: dnmr on June 06, 2010, 06:38:04 am
how does it crash? And why are you so sure it's this exact piece of code that's doing it?
Title: Re: Question Thread
Post by: DarkCrusade on June 06, 2010, 07:20:09 am
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:

Code: [Select]
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.
Title: Re: Question Thread
Post by: dnmr on June 06, 2010, 01:34:50 pm
try changing line 88 to
Code: (pascal) [Select]
    if GetPlayerStat(Yah, 'Active') = true then begin
Edit: line 74 to
Code: (pascal) [Select]
  Player: Array [0..32] of Stats;
Title: Re: Question Thread
Post by: squiddy on June 06, 2010, 02:11:35 pm
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
Title: Re: Question Thread
Post by: dnmr on June 06, 2010, 02:29:17 pm
@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 ::)
Title: Re: Question Thread
Post by: Serial K!ller on June 06, 2010, 02:50:48 pm
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.
Title: Re: Question Thread
Post by: DarkCrusade on June 06, 2010, 03:36:10 pm
@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

Title: Re: Question Thread
Post by: Serial K!ller on June 06, 2010, 04:28:17 pm
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.
Title: Re: Question Thread
Post by: DarkCrusade on June 07, 2010, 05:05:53 am
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?
Title: Re: Question Thread
Post by: Hacktank on June 07, 2010, 06:04:33 am
Pass the damage from onplayerdamage to dovamp():
Code: [Select]
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...
Title: Re: Question Thread
Post by: DarkCrusade on June 07, 2010, 06:23:45 am
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)
Title: Re: Question Thread
Post by: Hacktank on June 07, 2010, 07:00:03 am
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.
Title: Re: Question Thread
Post by: Swompie on June 07, 2010, 07:13:59 am
How do I detect a kill by a grenade?
You dont, not until 1.5.1 anyway...
You can:
Code: [Select]
if Weapon = 'Grenage' then
  WriteConsole(0, 'It was a grenade \o/', color);
Title: Re: Question Thread
Post by: DarkCrusade on June 07, 2010, 08:41:16 am
@HackTank: Works after adding Victim <> Shooter, thank you :)
@Swompie: Didn't know that that's possible.. lol

EDIT:

Code: (pascal) [Select]
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;

Code: [Select]
10-06-07 17:04:50  [*] RandomWar -> [Error] (488:3): Unknown identifier 'grenade'
Title: Re: Question Thread
Post by: Swompie on June 07, 2010, 10:39:52 am
(hint: weapon var is a string)
Title: Re: Question Thread
Post by: DarkCrusade on June 07, 2010, 10:45:26 am
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..
Title: Re: Question Thread
Post by: dnmr on June 07, 2010, 02:46:25 pm
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 ._.
Title: Re: Question Thread
Post by: DarkCrusade on June 07, 2010, 02:56:58 pm
I'd like to use the .ini actually
Title: Re: Question Thread
Post by: squiddy on June 07, 2010, 07:13:01 pm
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:

Code: (pascal) [Select]
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.
Title: Re: Question Thread
Post by: DarkCrusade on June 08, 2010, 10:39:13 am
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..
Title: Re: Question Thread
Post by: mich1103 on June 08, 2010, 03:01:51 pm
Do your zombie survival script is done ?
Title: Re: Question Thread
Post by: DarkCrusade on June 08, 2010, 11:46:26 pm
Still in work ;)
Title: Re: Question Thread
Post by: mich1103 on June 09, 2010, 04:01:48 pm
ok... so good working  :P
i can't wait to play your server :D
Title: Re: Question Thread
Post by: DarkCrusade on July 17, 2010, 06:35:25 am
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:

Code: [Select]
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().
Title: Re: Question Thread
Post by: Swompie on July 17, 2010, 06:39:04 am
Wasn't there a similar script already?
Title: Re: Question Thread
Post by: DarkCrusade on July 18, 2010, 11:33:45 am
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.
Title: Re: Question Thread
Post by: Swompie on July 18, 2010, 12:00:48 pm
FormatDate...
Title: Re: Question Thread
Post by: Falcon` on July 19, 2010, 06:42:33 pm
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:
Code: [Select]
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

Code: [Select]
10-07-17 13:27:42  [*] [Error] MapEnchantments -> (AppOnIdle): Could not call proc
Line 43: remove Len and replace with DeltaFireRegions.
Title: Re: Question Thread
Post by: DarkCrusade on July 20, 2010, 02:09:26 am
Sounds reasonable, thanks!