Here is a complex sample taken from Sarmates! that make waves of baddies
Sarmatians and allies must hold a position for 8 hours, repelling 4 waves of roman soldiers. The beauty of the thing is that if you have repelled a wave you can heal allies and/or ask them to pull back to cover before the following attack starts.
The initialization script (OnEnterConnect) sets the main variables : waves, hours and number of allies. A simple placeable tagged plot carries the key variables.
// enter Carnuntum area, first time : set time, count allied, fire convo
#include "ginc_misc"
void main()
{
object oPC = GetFirstPC();
if (IsMarkedAsDone()) return;
object oSign = GetObjectByTag("sign_carnuntum");
SetTime(7, 0, 0, 0);
SetLocalInt(oSign, "Hour", 8);
SetLocalInt(oSign, "Countdown", 4);
int n = 0;
object oIazyge = GetObjectByTag("iazyge_carnuntum");
while (GetIsObjectValid(oIazyge))
{
n++;
oIazyge = GetObjectByTag("iazyge_carnuntum", n);
}
SetLocalInt(oSign, "Allied", n);
DelayCommand(0.3f, AssignCommand(oPC, ActionStartConversation(GetObjectByTag("galatos"), "cv_galatos")));
MarkAsDone();
}
The main script, put on the area’s heartbeat, monitors the spawning of waves of baddies and the overall battle. At the end the more surviving allies, the more prestige for you commander. Actual reward is granted in a post combat convo.
// spawn new assaulters at hour change (recurrent - area)
void SpawnAt(string sFromWP, string sToWP)
{
int n = 0;
string sRef;
object oSoldier;
object oToWP = GetObjectByTag(sToWP);
object oWP = GetObjectByTag(sFromWP);
while (GetIsObjectValid(oWP))
{
switch (Random(6))
{
case 0 :
case 1 : sRef = "roman_fighter"; break;
case 2 :
case 3 : sRef = "roman_ranger"; break;
case 4 : sRef = "roman_cleric"; break;
case 5 : sRef = "roman_spadassin"; break;
}
oSoldier = CreateObject(OBJECT_TYPE_CREATURE, sRef, GetLocation(oWP));
AssignCommand(oSoldier, ActionForceMoveToObject(oToWP, TRUE, 8.0f, 24.0f));
n++;
oWP = GetObjectByTag(sFromWP, n);
}
}
void main()
{
object oPC = GetFirstPC();
if (GetJournalEntry("q_danube", oPC) != 110) return; // done or too early
object oSign = GetObjectByTag("sign_carnuntum");
int h = GetTimeHour();
if (h <= GetLocalInt(oSign, "Hour")) return;
SetLocalInt(oSign, "Hour", h+1);
int c = GetLocalInt(oSign, "Countdown") - 1;
SetLocalInt(oSign, "Countdown", c);
string s;
if (c > 0)
{
SpawnAt("WPS_carnuntum_left", "WP_carnuntum_left");
SpawnAt("WPS_carnuntum_right", "WP_carnuntum_right");
s = (GetGlobalInt("FR")) ? "Nouveaux renforts romains. Heure(s) à, tenir : " : "New Roman reinforcments. Hour(s) left : ";
SendMessageToPC(GetFirstPC(FALSE), s + IntToString(2*c));
return;
}
AddJournalQuestEntry("q_danube", 120, oPC); // all done, journal + compute prestige
c = 0;
h = 0;
object oIazyge = GetObjectByTag("iazyge_carnuntum");
while (GetIsObjectValid(oIazyge))
{
if (!GetIsDead(oIazyge)) c++;
h++;
oIazyge = GetObjectByTag("iazyge_carnuntum", h);
}
h = GetLocalInt(oSign, "Allied");
if ((c * 100) > (h * 50)) c = 2;
else if ((c * 100) > (h * 25)) c = 1;
else c = 0;
SetLocalInt(oSign, "Allied", c);
}
The scripts may look scary at first. If you go in depth you may find them helpful.