- Posts: 746
- Thank you received: 569
Random Scripting Introduction
- Stern
- Topic Author
- Offline
Less
More
4 years 1 week ago - 4 years 1 week ago #1
by Stern
The one who hesitates is lost !
Random Scripting Introduction was created by Stern
Well then, I present some ideas and script examples about how to randomize mission.
First things first:
This is not scripting tutorial !
(It requires some basic knowledge of HD2 scripting language functionality)
I like to use Notepad++
(Use this for Notepad++ to support HD2 script (*SCR) added to C++ language.)
(All script examples presented here are already used in some missions, changed to fit this tutorial)
(Some parts of script examples might not be present, like object framing and variable declaration)
*
Scripting is the way to make mission function as a mission.
Almost everything that moves/acts or changes in running mission is scripted.
Randomness creates many useful variations to make mission act different each time you play it.
Mission with controlled variations will be interesting
and will not get boring when played many many times...
But time is money so I get right to the point then:
[hr]
Random spawn(activation) of enemy/ally.
There are mainly 2 ways to make enemy activation random.
1.
One script controls some or all enemy spawns.
This script might detect player with commands: "_PlayerInBox" or "_PlayerInRange"
Or it can be set at mission start or by other means.
Example (Random snipers)
2.
Other way:
Every enemy has its own random spawn section in script.
*Never use HUMAN_MoveRandomRadius() or any other time dependent command inside BLOCK{} when other command follows !
BLOCK{} does not wait command to run to the end.
*Rnd1 variable is re-used many times here, its fine unless the variable has to hold the value after next need for a variable.
Then sepatate varables must be used.
Disadvantage of this spawn method is that its not possible to check killed enemy directly.
One way to get around it is to kill "Not spawned" enemy.
NB_! Enemy should have weapon on shoulder at mission start, if not then weapon will drop on the ground near enemy position !
Can use this:
HUMAN_WeaponOnArm(0);
Before HUMAN_Kill(me);
For this use: GetMyFrame:
Frame me; FRM_GetMyFrame(me);
and use HUMAN_Kill(me); in "Not spawned" section:
Now its possible to check killed enemy with command "(!_EnemyInRange())"
*One simple and short way to count killed enemy (uses only one variable S1):
Make enemy movement ability random (OnAlarm):
This requires that enemy is set to "HUMAN_SETAIMODE_Zombie();"
And can be set back to "HUMAN_SETAIMODE_Zombie();" in the "OnAlarmDone()" section.
This way the same enemy might be passive at next Alarmed state.
Random (selected) equipment:
This is the equipment that Player can find in killed enemy inventory.
Random Ammoboxes
Ammo/equipment box should be set to be delivered by parachute.
And the location should have open sky above it.
Start position can be under the surface to hide the box.
Random Objectives:
*Used in Libya1(PrisonBreak)
Random objectives meaning will be lost in very small areas like Libya1.
Its much better to use it for large areas,
where Player can skip going to some areas
if objectives does not require to go there.
Walking guard
Needs some dummy objects in Actors.bin.
"gosub" (procedure/function in prog. language)
is useful if this code (delay in this case) is used from other places in script,
then this code is present in only one place, and script can be directed to use it from any places.
Maybe this helps to get ideas or get start to manage some random acts in mission.
First things first:
This is not scripting tutorial !
(It requires some basic knowledge of HD2 scripting language functionality)
I like to use Notepad++
This attachment is hidden for guests.
Please log in or register to see it.
Please log in or register to see it.
(Use this for Notepad++ to support HD2 script (*SCR) added to C++ language.)
(All script examples presented here are already used in some missions, changed to fit this tutorial)
(Some parts of script examples might not be present, like object framing and variable declaration)
*
Scripting is the way to make mission function as a mission.
Almost everything that moves/acts or changes in running mission is scripted.
Randomness creates many useful variations to make mission act different each time you play it.
Mission with controlled variations will be interesting
and will not get boring when played many many times...
But time is money so I get right to the point then:
[hr]
Random spawn(activation) of enemy/ally.
There are mainly 2 ways to make enemy activation random.
1.
One script controls some or all enemy spawns.
This script might detect player with commands: "_PlayerInBox" or "_PlayerInRange"
Or it can be set at mission start or by other means.
Example (Random snipers)
Warning: Spoiler!
Code:
//Actiate atleast 2 scipers
counter1=0;
Label RandomSnipers:
gosub RndSelect; sendsignal (Sniper01,rnd1); //Send signal 1/0 to enemy script ("rnd1" value) SendSignal(1)=Suspend(0)
gosub RndSelect; sendsignal (Sniper02,rnd1);
gosub RndSelect; sendsignal (Sniper03,rnd1);
gosub RndSelect; sendsignal (Sniper04,rnd1);
gosub RndSelect; sendsignal (Sniper05,rnd1);
if (counter1<2) {goto RandomSnipers;} //check if variabe "counter1" has reached desired value, if not go to next round
else {goto Count;} //"goto Count" can be something else ! Here it goes to section that counts killed enemy.
Label RndSelect: //"gosub" sets script to this line
rnd1=(_randomint(2)); //Random 0 or 1, 1 to Spawn sniper
counter1=counter1+rnd1; //Add 0 or 1 from previous line (Variable "rnd1").
return; //"return" sets script back to line where it came from
//2.part of example: Counting killed enemy
Label Count:
C1=0; //C1 (integer variable) Sets to "0" at start of every round, it stores number of killed enemy.
if (_ACTOR_GetState(Sniper01)==0) {C1=C1+1;} //add 1 to C1 if _ACTOR_GetState=0 (enemy killed)
if (_ACTOR_GetState(Sniper02)==0) {C1=C1+1;}
if (_ACTOR_GetState(Sniper03)==0) {C1=C1+1;}
if (_ACTOR_GetState(Sniper04)==0) {C1=C1+1;}
if (_ACTOR_GetState(Sniper05)==0) {C1=C1+1;}
//printfnumber("C1: ",C1);
if (C1==counter1) //Check if C1 (already killed enemy) is equal to activated enemy (from 1. part of example).
{SendSignal(objectives, 8); goto END;} //If C1==counter1 do something...
delay(30000); //Just some delay
goto Count; //If not equal go to next round.
2.
Other way:
Every enemy has its own random spawn section in script.
Warning: Spoiler!
Code:
Whenever Spawn (_PlayerInRange(85)) //Detects if Player is in radius of given distance
{
Rnd1=(_randomint(3)); //1 out of 3 chance Not to spawn
if (Rnd1==2)
{
goto END;
}
else
{
Block
{
HUMAN_Suspend(0); //Activate
Rnd1=(_randomint(30)+70); //75 to 100
HUMAN_SETSIGHTRANGE(Rnd1); //Set random SIGHTRANGE
Rnd1=(_randomint(30)+50); //50 to 80
HUMAN_SETHEARRANGE(Rnd1); //Set random HEARRANGE
HUMAN_WeaponOnArm(0);
HUMAN_SETAIMODE_Zombie();
}
HUMAN_MoveRandomRadius(5); //Move random radius to add variations to enemy final position after spawn.
//...add your code
}
}
*Never use HUMAN_MoveRandomRadius() or any other time dependent command inside BLOCK{} when other command follows !
BLOCK{} does not wait command to run to the end.
*Rnd1 variable is re-used many times here, its fine unless the variable has to hold the value after next need for a variable.
Then sepatate varables must be used.
Disadvantage of this spawn method is that its not possible to check killed enemy directly.
One way to get around it is to kill "Not spawned" enemy.
NB_! Enemy should have weapon on shoulder at mission start, if not then weapon will drop on the ground near enemy position !
Can use this:
HUMAN_WeaponOnArm(0);
Before HUMAN_Kill(me);
For this use: GetMyFrame:
Frame me; FRM_GetMyFrame(me);
and use HUMAN_Kill(me); in "Not spawned" section:
Warning: Spoiler!
Code:
Whenever Spawn (_PlayerInRange(85))
{
Rnd1=(_randomint(3));
if (Rnd1==2)
{
HUMAN_WeaponOnArm(0);
HUMAN_Kill(me);
goto END;
}
Now its possible to check killed enemy with command "(!_EnemyInRange())"
*One simple and short way to count killed enemy (uses only one variable S1):
Warning: Spoiler!
Code:
label CountLoop:
S1=0; //Integer variable, set to 0 at start of every new counting round.
Block
{
S1=S1+_Actor_GetState(Eenemy01); //Add "_Actor_GetState" value to S1 (0 or 1)
S1=S1+_Actor_GetState(Eenemy02);
S1=S1+_Actor_GetState(Eenemy03);
S1=S1+_Actor_GetState(Eenemy04);
S1=S1+_Actor_GetState(Eenemy05);
S1=S1+_Actor_GetState(Eenemy06);
S1=S1+_Actor_GetState(Eenemy07);
S1=S1+_Actor_GetState(Eenemy08);
S1=S1+_Actor_GetState(Eenemy09);
S1=S1+_Actor_GetState(Eenemy10);
S1=S1+_Actor_GetState(Eenemy11);
S1=S1+_Actor_GetState(Eenemy12);
S1=S1+_Actor_GetState(Eenemy13);
S1=S1+_Actor_GetState(Eenemy14);
S1=S1+_Actor_GetState(Eenemy15);
}
//PrintfNumber("S1: ",S1); //Printf number if need to see current value in-game.
If (S1==0) //check if S1=0 (all enemy killed)
{
... //Do something when S1=0
goto end;
}
else
{
Delay(10000);
goto CountLoop; //go to next round if S1 is not "0"
}
Make enemy movement ability random (OnAlarm):
Warning: Spoiler!
Code:
OnAlarm()
{
Rnd1=(_randomint(30));
If ((Rnd1 == 1) or (Rnd1 == 2) or (Rnd1 == 3) or (Rnd1 == 4) or (Rnd1 == 5)) //5 out of 30 chance to Defensive mode.
{
HUMAN_SETAIMODE_Defensive();
}
If (Rnd1 == 10) //1 out of 30 chance to Aggressive mode.
{
HUMAN_SETAIMODE_Aggressive();
}
EndScript();
}
This requires that enemy is set to "HUMAN_SETAIMODE_Zombie();"
And can be set back to "HUMAN_SETAIMODE_Zombie();" in the "OnAlarmDone()" section.
This way the same enemy might be passive at next Alarmed state.
Random (selected) equipment:
Warning: Spoiler!
Code:
OnDeath()
{
Rnd1=(_randomint(10)); //Small possibility to have additional items added.
if (Rnd1==2){HUMAN_CreateItemInStore(54, 1);} //First-Aid kit
if (Rnd1==4){HUMAN_CreateItemInStore(61, 1);} //Stielhandgranate 39
if (Rnd1==6){HUMAN_CreateItemInStore(66, 1);} //Sticky bomb
if (Rnd1==8){HUMAN_CreateItemInStore(68, 1);} //Dynamite
EndScript();
}
This is the equipment that Player can find in killed enemy inventory.
Random Ammoboxes
Ammo/equipment box should be set to be delivered by parachute.
And the location should have open sky above it.
Start position can be under the surface to hide the box.
Warning: Spoiler!
Code:
Rnd1=(_randomint(5));
if (Rnd1==1) // 1 chance from 5 to activate box.
{
SetActorState(AmmoBox01, 1); //Activate box.
}
Rnd1=(_randomint(5));
if (Rnd1==1)
{
SetActorState(AmmoBox02, 1);
}
Rnd1=(_randomint(5));
if (Rnd1==1)
{
SetActorState(AmmoBox03, 1);
}
//No need to use variable for random number, IF statement will accept it directly.
if (_randomint(5)==1)
{
SetActorState(AmmoBox01, 1);
}
Random Objectives:
*Used in Libya1(PrisonBreak)
Warning: Spoiler!
Code:
SaveGameValue(1, 0);
SaveGameValue(2, 0);
SaveGameValue(3, 0);
SaveGameValue(4, 0);
SaveGameValue(5, 0);
SaveGameValue(6, 0);
SaveGameValue(7, 0);
SaveGameValue(8, 0);
SetObjectiveStatus(1, 4);
SetObjectiveStatus(2, 4);
SetObjectiveStatus(3, 4);
SetObjectiveStatus(4, 4);
SetObjectiveStatus(5, 4);
SetObjectiveStatus(6, 4);
SetObjectiveStatus(7, 4);
SetObjectiveStatus(8, 4);
//SetObjectiveStatus(9, 4);
//variables needed:
Integer NumOfObj;
Integer rnd2; //0 or 1 (1 to activate Objective)
Integer counter1; //counts from 1 to 8 (max 8 random Objectives)
Integer counter2; //counts activated Objectives to compare with NumOfObj
counter1=0;
counter2=0;
NumOfObj=(_randomint(3)+3); //minimum number of Objectives
//----------------------Random Objectives----------------------
Label ObjLoop:
gosub RndObj; //goes to sub-label: RndObj 1. time
gosub RndObj;
gosub RndObj;
gosub RndObj;
gosub RndObj;
gosub RndObj;
gosub RndObj;
gosub RndObj;
if (counter2<NumOfObj) //check if number of active objectives is less than "NumOfObj"
{
counter1=0; //Reser counter
goto ObjLoop; //Start loop
}
else
{
//goto SetObjs;
//***go forward if reached over or equal to minimum number of active Objectives
}
Label RndObj:
counter1=counter1+1; //counter1 gets +1 every time "gosub RndObj" is used.
rnd2=(_randomint(2)); //generate randoom number: 0 or 1
if ((rnd2==1)and(_LoadGameValue(counter1)==0)) //if random = 1 and GameValue=0 (Objective not yet activated)
{
SetObjectiveStatus(counter1, 0); //Set ObjectiveStatus to 0 (Not completed) for the Objective given by "counter1"
SaveGameValue(counter1, 1); //Set 1 to SaveGameValue at "counter1" to flag it as "Activated"
counter2=counter2+1; //count each activated Objective only 1 time!!! (add+1 if Objective Activated)
}
return;
Random objectives meaning will be lost in very small areas like Libya1.
Its much better to use it for large areas,
where Player can skip going to some areas
if objectives does not require to go there.
Walking guard
Needs some dummy objects in Actors.bin.
Warning: Spoiler!
Code:
frame dummy_1; FRM_FindFrame(dummy_1,"dummy_1");
frame dummy_2; FRM_FindFrame(dummy_2,"dummy_2");
frame dummy_3; FRM_FindFrame(dummy_3,"dummy_3");
//This random walking guard can be set to start after spawn section.
HUMAN_SETMODE_Guard(); //set to slow walk
goto checkpoint1;
//
label checkpoint1:
HUMAN_MoveToFrame(dummy_1, 2); //move to dummy
gosub delay; //go to Delay
rndcp=(_randomint(2)); //select one or other ceckpoint to be next
if (rndcp==0)
{
goto checkpoint2;
}
if (rndcp==1)
{
goto checkpoint3;
}
label checkpoint2:
HUMAN_MoveToFrame(dummy_2, 2); //move to dummy
gosub delay;
rndcp=(_randomint(2));
if (rndcp==0)
{
goto checkpoint1;
}
if (rndcp==1)
{
goto checkpoint3;
}
label checkpoint3:
HUMAN_MoveToFrame(dummy_3, 2);
gosub delay;
rndcp=(_randomint(2));
if (rndcp==0)
{
goto checkpoint1;
}
if (rndcp==1)
{
goto checkpoint2;
}
//----delay----
label delay:
rndpause=(_randomint(10000)+5000);
delay(rndpause);
return;
"gosub" (procedure/function in prog. language)
is useful if this code (delay in this case) is used from other places in script,
then this code is present in only one place, and script can be directed to use it from any places.
Maybe this helps to get ideas or get start to manage some random acts in mission.
The one who hesitates is lost !
Last edit: 4 years 1 week ago by Stern.
The following user(s) said Thank You: snowman, Damni, WANGER
Please Log in or Create an account to join the conversation.
- snowman
- Offline
- Your most dear friend.
4 years 1 week ago #2
by snowman
"Straight and narrow is the path."
Replied by snowman on topic Random Scripting Introduction
This is excellent work, Stern. I feel this deserves it's own topic
Very clearly explained
Very clearly explained
"Straight and narrow is the path."
The following user(s) said Thank You: Stern
Please Log in or Create an account to join the conversation.
Birthdays
- Tecnom
- Hellcat in 3 days
- Winters in 4 days
- Alexliberty in 5 days
- Mizha in 9 days
- British Bulldog in 10 days