Re: Dynamic Script Usage
PostPosted: 19 Apr 2013, 03:09
Spawner is a group ID, not a unit ID. UnitHungerSet is expecting a unit ID. You need to use a for-loop and run UnitHungerSet on every unit in the group (using GroupMember)
Talk about Knights and Merchants!
https://knightsandmerchants.net:443/forum/
https://knightsandmerchants.net:443/forum/viewtopic.php?t=1489
Is there a way to automatically detect all units on the map?
var
{used by ScreenText}
LibxTextQueue: array [1..100] of array [1..4] of integer; //100 vertical and 4 horizontal
StringTextQueue: array[1..100] of string;
procedure ScreenText(DesiredAction: string; PlayerID: integer; Duration: integer; LibxEntry: integer; DirectStringInput: string);
{This procedure generates text on the screen through Actions.SetOverLayText. valid input:
1st parameter, DesiredAction: 'OnNewLine, OnSameLine, OnTopLine, ResetAndNewLine, UpdateScreenText'
2nd parameter, PlayerID: -1 for all players, 0..7 for specific player
3rd parameter, Duration: 1..any integer for the duration, in seconds
4th parameter, LibxEntry: index of [missionname].libx file to be shown, or -1 if direct string input in 5th parameter
5th parameter, DirectStringInput: alternatively, use a direct string input here. Note: use -1 for 4th parameter.
Example call: ScreenText('OnNewLine',2,5,-1,'This is my custom message');}
var
VerticalCounter: integer;
HorizontalCounter: integer;
DownShiftCounter: integer;
PlayerCounter: integer;
FirstEmptySlot: integer;
DeletedRows: integer;
TheOverlayText: string;
NewLineSpace: string;
begin
{Start by checking if the input parameters make sense}
// check 1st parameter
if not((DesiredAction = 'OnNewLine') or (DesiredAction = 'OnSameLine') or (DesiredAction = 'OnTopLine') or (DesiredAction = 'ResetAndNewLine') or (DesiredAction = 'UpdateScreenText')) then begin
for PlayerCounter := 0 to 7 do begin
Actions.ShowMsg(PlayerCounter,'Error! Procedure ScreenText was called with an invalid first parameter for the intended action (' + DesiredAction + '). Use single quotes and enter either: OnNewLine, OnSameLine, OnTopLine, ResetAndNewLine or UpdateScreenText.');
exit;
end;
end;
// check 2nd parameter
if (PlayerID<-1) or (PlayerID>7) then begin
Actions.ShowMsg(PlayerCounter,'Error! Procedure ScreenText was called with an invallid second parameter for the intended player ID (' + IntToStr(PlayerID) + '). Use -1 for all players, or 0 up to 7 for a specific player');
exit;
end;
//check 3rd parameter
if (Duration <= 0) and not (DesiredAction = 'UpdateScreenText') then begin
Actions.ShowMsg(PlayerCounter,'Error! Procedure ScreenText was called with an invallid third parameter for the intended message duration (' + IntToStr(Duration) + '). Enter any integer larger than 0. Duration is in seconds, not in ticks!');
exit;
end;
// check 4th paramter
if LibxEntry <-1 then begin
Actions.ShowMsg(PlayerCounter,'Error! Procedure ScreenText was called with an invallid fourth parameter for the entry in the [missionname].libx file (' + IntToStr(LibxEntry) + '). Usage 1: any integer larger or equal to 0. Usage 2: type in -1, in combination with a custom string in the fifth parameter.');
exit;
end;
//check 5th parameter
if (LibxEntry >= 0) and not (DirectStringInput = '') then begin
Actions.ShowMsg(PlayerCounter,'Error! Procedure ScreenText was called with the fourth parameter (' + IntToStr(LibxEntry) + ') and the fifth parameter with the non-empty string (' +DirectStringInput+ '). Please provide: -1 (4th argument) and string (5th parameter). Or provide: 0..any number (4th parameter) and no string (5t parameter).');
exit;
end;
{if input is OnNewLine, OnSameLine, OnTopLine or UpdateScreenText find length of queued texts}
if (DesiredAction = 'OnNewLine') or (DesiredAction = 'OnSameLine') or (DesiredAction = 'OnTopLine') or (DesiredAction = 'UpdateScreenText')then begin
for VerticalCounter := 1 to 100 do begin
if LibxTextQueue[VerticalCounter][2] = 0 then begin
FirstEmptySlot := VerticalCounter;
break;
end;
end;
end;
{If input is ResetAndNewLine then clear all texts}
if (DesiredAction = 'ResetAndNewLine') then begin
for VerticalCounter := 1 to 100 do begin
for HorizontalCounter := 1 to 4 do begin
LibxTextQueue[VerticalCounter][HorizontalCounter] := 0;
end;
StringTextQueue[VerticalCounter] := '';
end;
FirstEmptySlot := 1;
DesiredAction := 'OnNewLine';
end;
{If OnNewLine, OnSameLine or OnTopLine then add to queue}
if (DesiredAction = 'OnNewLine') or (DesiredAction = 'OnSameLine') or (DesiredAction = 'OnTopLine') then begin
LibxTextQueue[FirstEmptySlot][1] := PlayerID;
LibxTextQueue[FirstEmptySlot][3] := States.GameTime + (Duration*10);
if DesiredAction = 'OnNewLine' then LibxTextQueue[FirstEmptySlot][2] := 1; //1 means: OnNewLine
if DesiredAction = 'OnSameLine' then LibxTextQueue[FirstEmptySlot][2] := 2; //2 means: OnSameLine
if DesiredAction = 'OnTopLine' then LibxTextQueue[FirstEmptySlot][2] := 3; //3 means: OnTopLine
LibxTextQueue[FirstEmptySlot][4] := LibxEntry;
if LibxEntry >= 0 then begin
StringTextQueue[FirstEmptySlot] := '';
end;
if LibxEntry = -1 then begin
StringTextQueue[FirstEmptySlot] := DirectStringInput;
end;
end;
{If 'UpdateScreenText' then refresh overlay text on screen}
if DesiredAction = 'UpdateScreenText' then begin
{First, search for strings that need to be deleted}
for VerticalCounter := 1 to (FirstEmptySlot-1) do begin
// if gametime larger than indicated deletetime then delete corresponding text
if (LibxTextQueue[VerticalCounter][3] >0) and (States.GameTime >= LibxTextQueue[VerticalCounter][3]) then begin
for DownShiftCounter := VerticalCounter to (FirstEmptySlot-1) do begin
for HorizontalCounter := 1 to 4 do begin
LibxTextQueue[DownShiftCounter][HorizontalCounter] := LibxTextQueue[DownShiftCounter+1][HorizontalCounter];
end;
StringTextQueue[DownShiftCounter] := StringTextQueue[DownShiftCounter+1];
end;
VerticalCounter := VerticalCounter - 1;
end;
end;
{Second, process all queued text and actually generate the overlay text}
for PlayerCounter := 0 to 7 do begin
TheOverlayText := '';
for VerticalCounter := 1 to (FirstEmptySlot - DeletedRows) do begin
if (LibxTextQueue[VerticalCounter][1] = PlayerCounter) or (LibxTextQueue[VerticalCounter][1] = -1) then begin
// Add newline character if OnNewLine or OnTopLine and not first line
if ((LibxTextQueue[VerticalCounter][2] = 1) or (LibxTextQueue[VerticalCounter][2] = 3)) and (VerticalCounter>1) then NewLineSpace := '|';
// if OnNewLine and libx index 0 or bigger provided
if (LibxTextQueue[VerticalCounter][2] = 1) and (LibxTextQueue[VerticalCounter][4] >= 0) then TheOverlayText := TheOverlayText + NewLineSpace + States.Text(LibxTextQueue[VerticalCounter][4]) + ' ';
// if OnNewLine and libx index -1 provided
if (LibxTextQueue[VerticalCounter][2] = 1) and (LibxTextQueue[VerticalCounter][4] = -1) then TheOverlayText := TheOverlayText + NewLineSpace + StringTextQueue[VerticalCounter] + ' ';
// if OnSameLine and libx index 0 or bigger provided
if (LibxTextQueue[VerticalCounter][2] = 2) and (LibxTextQueue[VerticalCounter][4] >= 0) then TheOverlayText := TheOverlayText + States.Text(LibxTextQueue[VerticalCounter][4]) + ' ';
// if OnSameLine and libx index -1 provided
if (LibxTextQueue[VerticalCounter][2] = 2) and (LibxTextQueue[VerticalCounter][4] = -1) then TheOverlayText := TheOverlayText + StringTextQueue[VerticalCounter] + ' ';
// if OnTopLine and libx index 0 or bigger provided
if (LibxTextQueue[VerticalCounter][2] = 3) and (LibxTextQueue[VerticalCounter][4] >= 0) then TheOverlayText := States.Text(LibxTextQueue[VerticalCounter][4]) + NewLineSpace + TheOverlayText + ' ';
// if OnTopLine and libx index -1 provided
if (LibxTextQueue[VerticalCounter][2] = 3) and (LibxTextQueue[VerticalCounter][4] = -1) then TheOverlayText := StringTextQueue[VerticalCounter] + NewLineSpace + TheOverlayText + ' ';
end;
Actions.SetOverLayText(PlayerCounter,TheOverlayText);
end;
end;
end;
end;
procedure onTick;
begin
if States.GameTime = 10 then ScreenText('OnNewLine',-1,10,-1,'This is message 1, show me for ten seconds!');
if States.GameTime = 30 then ScreenText('OnNewLine',-1,10,-1,'This is message 2, show me for ten seconds!');
if States.GameTime = 50 then ScreenText('OnSameLine',-1,10,-1,'This is message 3, on the same line!');
if States.GameTime = 70 then ScreenText('OnNewLine',-1,10,-1,'Message 4!');
if States.GameTime = 70 then ScreenText('OnNewLine',-1,2,-1,'Message 5 at the same time! But I am only visible for 2 seconds!');
if States.GameTime = 110 then ScreenText('ResetAndNewLine',-1,10,-1,'I am deleting all previous messages!');
if States.GameTime = 130 then ScreenText('OnTopLine',-1,10,-1,'I am later but get to be on top!');
if States.GameTime mod 5 = 0 then ScreenText('UpdateScreenText',-1,-1,-1,'');
end;
We don't want to allow global string variables, because that would make MP saves incompatible if they were saved from different locales.
Thanks for bringing that up Philymaster. Short circuit evaluation is enabled by default in Delphi and Lazarus, we use it all the time in the KaM Remake code. However, the PascalScript interpreter has it disabled by default for some reason... I've enabled it now so in the next RC code like you wrote will work
The freezing and low performance is possibly because it is generating a lot of errors that are written to the log files. Open up the latest file in the Logs folder and scroll to the bottom, see if there are script errors (in this case it will complain that you used GroupOwner with -1 as the GroupID, because it's not using short circuit evaluation)