warzone2100/data/script/text/genexp.slo

2143 lines
65 KiB
Plaintext
Raw Normal View History

//Generic script Version 1.0
//GenExp.slo
//For start/expand campaign maps
/* ******************** */
/* Declared Variables */
/* ******************** */
/* Next Level stuff */
public LEVEL NextLev;
public BOOL lastLev;
/* Define Players/Enemies */
public int numEnemies, enemy[2], allianceEnemy[2], alliancePlayer;
private int targetCount[2], targetX[2][5], targetY[2][5]; //MAX targets = 4, need array one bigger!
public BOOL allianceFlag;
/* Starting Enemy Power */
public int power[2];
/* Starting health retreat setting*/
public int healthRetreat[2], healthRetreatX[2], healthRetreatY[2];
public BOOL runOffFlag;
/* Structure Limits */
public int numStrucStats, strucLimit[6];
public STRUCTURESTAT strucStat[6];
/* Initialisation */
public int centreX, centreY;
public int scrollX1, scrollX2, scrollY1, scrollY2;
public int zoomLevel;
public int numLZ, LZX[8], LZY[8];
public int numTechs[2];
public RESEARCHSTAT startTech[2][40];
/* Transport Entry/Exit coords */
public int transX[2], transY[2]; //done in arrays so don't need to define for non submaps
//transX[0] = entryX, transX[1] = exitX
public INT ReinforceTime, timeLimit;
public int entryX[2], entryY[2], exitX[2], exitY[2]; //enemy transport entry, exit
public TEMPLATE transporter; //required for enemy transports landing
private DROID transportDroid[2];
private BOOL transOnMap[2], playerTransOnMap, reinfOff;
private GROUP transGroup;
private INT transGroupIndex[2], transGroupPlayer, enemyLZX, enemyLZY; //used for enemy transports landing
/* Videos - should only be max of two - and that's for the PSX - actually we need 8 (cam1->2)!*/
public int numVideos;
public TEXTSTRING video[8];
public TEXTSTRING videoText[8];
/* Briefings */
public int numBriefs, briefVal[5];
public INTMESSAGE brief[5];
public INTMESSAGE endMsg;
/* Victory Conditions */
public int numVictory, victory[4];
public BOOL linkVictory, linkFail; //extra victories checked in other scripts
/* Failure Conditions */
public int fail[2];
public SOUND failSnd;
public TEXTSTRING failMsg;
/* Time Limit */
public BOOL noTimeLimit; //false = time limit fail OK, True = don't use time limit as fail
/* Objectives */
public int numObjectives, objectiveX[4], objectiveY[4];
public INTMESSAGE objective[4];
private BOOL objectiveFlag[4];
private int objectivesDone;
/* Artifacts */
public SOUND artSnd1, artSnd2;
public int numArt, victoryArt, artType[6], artVal[6], artX[6], artY[6];
//public INTMESSAGE artMsg[6];
public RESEARCHSTAT artComp[6];
private FEATURE artID[6];
private int artFlag[6];
private int artCollected;
/* Enemy Base Blips */
public int numBases, basePlayer[7];
public int baseRegion[7], baseWav1[7], baseWav2[7];
public INTMESSAGE baseMsg[7];
private int baseFlag[7];
private int basesDead;
/* Return to LZ Stuff */
public BOOL retLZFlag; //must be set to have any affect
public SOUND retLZSnd; //audio to play
public INTMESSAGE retLZBlip; //LZ blip
public TEXTSTRING retLZMsg; //text message "Return to LZ"
/* Groups */
//these can be for any player!
public int numGroups;
public int grpType[10], grpPlayer[10], grpRegion[10], grpTimeGo[10], grpRegionGo[10], grpWhoGo[10];
public int grpMorale[10], grpLeadership[10], grpRetreatXY[10], grpIdealSize[10];
public int grpPosStart[10], grpPosMin[10], grpPosMax[10], grpPosStep[10], grpPosType[10];
public int grpFactory[10];
private BOOL grpFlagGo[10]; //keep track of already triggered groups
private GROUP grpGroup[10], grpReinforce[10]; //the actual groups are stored in this, based on region.
private int grpPosCurrent[10]; //keep track of current waypoint
private BOOL grpBusy[10]; //keep track of already ordered
private int timeGroup; //keeps track of time since started level, for triggering groups
/* Factories */
//these can be for any player!
public int numFactories;
public int factID[11], factAssXY[11], factTimeGo[11];
public int factRegionGo[11], factTempMin[11], factTempMax[11];
public int factEvery[11];
private BOOL factFlagGo[11]; //stores whether producing or not
private int factTime[11]; //store count for next production
/* LISTS OF STUFF (INDEXED BY ARRAY) */
public STRUCTURE structures[15];
public FEATURE features[10];
public DROID droids[10];
public TEMPLATE templates[20];
public int coordsX[20], coordsY[20];
public int regionsX1[20], regionsY1[20], regionsX2[20], regionsY2[20];
public int sectorsX1[20], sectorsY1[20], sectorsX2[20], sectorsY2[20];
/* 'Globals' */
public int player;
public FEATURESTAT crate;
public int artRange, objectiveRange; //artifact pickup/obj blip removal
public int wayRange, targetRange; //range to waypoints/range for targets
public int targetMax; //maximum number of targets (4)
public SOUND lostSnd; //mission lost
public SOUND attackSnd1; //Base Under Attack Sound
public SOUND baseSnd[5]; //base detected/dead
public SOUND transSnd; //enemy transport landing
public SOUND LZComp, LZClear;
public int LZRange;
/* General variables */
private int count, count2, count3; //for while loops
private DROID testDroid, newDroid;
private STRUCTURE newDroidFactory; //new droid built
private int newDroidFactoryIndex; //for phantom factories
private int countBriefs, temp, temp1, temp2, tempX, tempY;
private int countVideos;
private STRUCTURE hitStruc; //Base Under Attack
private BASEOBJ attackerObj; //Base Under Attack
private int t; //Base Under Attack time delay for next warning
private int enemyCount; //for enemy base attack stuff!
private FEATURE feature; //for building oil derricks on oil resources
/* Trucks stuff */
public BOOL trucksOn; //won't work without this set to TRUE!!!
public FEATURESTAT oilRes;
public int truckRange, defRange;
public int numDefences, numToDefend, maxDefence; //defences to build
public STRUCTURESTAT defences[5], toDefend[5];
private BOOL boolResult, truckFlag;
private GROUP truckGroup[2];
/* Threat Stuff */
public int threatLight, threatMedium, threatHeavy, threatRange;
/* ******************** */
/* Triggers */
/* ******************** */
/*
//triggers doubled (where possible) for PSX to reduce slowdown
trigger winTrig (artCollected >= victoryArt, 50);
trigger lostTrig (every, 50); //(not anyDroidsLeft(player), 25);
trigger objTrig (every, 30);
trigger artTrig (every, 20);
trigger baseTrig (every, 34);
trigger nextLevTrig (every, 38);
trigger gameLostTrig (every, 40);
trigger checkGroupsTrig (every, 70); //every 4 seconds
trigger wayGroupsTrig (every, 214); //every 10ish secs seconds (so don't get clogging!)
trigger sectorGroupsTrig(every, 150); //every 8 seconds
trigger attackGroupsTrig(every, 166); //every 8 seconds
trigger targetGroupsTrig(every, 86); //every 4 seconds
trigger regionGroupsTrig(every, 22); //every second
trigger timeGroupsTrig (every, 103); //every 10 seconds (made different so don't get clogging!)
trigger updateEnemyTrig (every, 42); //every 2 seconds
trigger factoryProdTrig (every, 97); //every 10 seconds (uses factTime to count this period and factEvery to trigger)
trigger droidBuiltTrig (wait, 1); //very quickly
trigger vidEndTrig (CALL_VIDEO_QUIT);
trigger transLandedTrig (CALL_TRANSPORTER_LANDED, transGroup, enemy[transGroupPlayer]);
trigger transGone1Trig (CALL_TRANSPORTER_OFFMAP, enemy[transGroupPlayer]);
trigger buildDerrickTrig(every, 200); //every 20 seconds
trigger buildDefencesTrig(every, 205); //every 20 seconds
trigger checkTrucksTrig (every, 290);
trigger checkLZTrig (every, 70); //for compromise/clear
trigger threatGroupsTrig(every, 194); //for threat analysis
*/
trigger winTrig (artCollected >= victoryArt, 25);
trigger lostTrig (every, 25); //(not anyDroidsLeft(player), 25);
trigger objTrig (every, 15);
trigger artTrig (every, 10);
trigger baseTrig (every, 17);
trigger nextLevTrig (every, 19);
trigger gameLostTrig (every, 20);
trigger checkGroupsTrig (every, 35); //every 4 seconds
trigger wayGroupsTrig (every, 107); //every 10ish secs seconds (so don't get clogging!)
trigger sectorGroupsTrig(every, 41); //every 4 //8 seconds
trigger attackGroupsTrig(every, 45); //every 4 //8 seconds
trigger targetGroupsTrig(every, 43); //every 4 seconds
trigger regionGroupsTrig(every, 11); //every second
trigger timeGroupsTrig (every, 100); //every 10 seconds (made different so don't get clogging!)
trigger updateEnemyTrig (every, 21); //every 2 seconds
trigger factoryProdTrig (every, 97); //every 10 seconds (uses factTime to count this period and factEvery to trigger)
trigger droidBuiltTrig (wait, 1); //very quickly
trigger vidEndTrig (CALL_VIDEO_QUIT);
trigger transLandedTrig (CALL_TRANSPORTER_LANDED, transGroup, enemy[transGroupPlayer]);
trigger transGone1Trig (CALL_TRANSPORTER_OFFMAP, enemy[transGroupPlayer]);
trigger buildDerrickTrig(every, 200); //every 20 seconds
trigger buildDefencesTrig(every, 205); //every 20 seconds
trigger checkTrucksTrig (every, 290);
trigger checkLZTrig (every, 35); //for compromise/clear
trigger threatGroupsTrig(every, 97); //for threat analysis
trigger RTLZStart(wait,0);
trigger RTLZFreq(every,300);
/* ******************** */
/* Events */
/* ******************** */
/* Declared Events */
event briefings;
event wonYetEvnt;
event lostYetEvnt;
event timeUp;
event droidBuilt;
event transLanded;
event transGone1;
event buildDerrick;
event checkTrucks;
event LZ_OK;
event LZNoGo;
event periodicRTLZ;
/* Initialisation */
event start(CALL_GAMEINIT)
{
randomiseSeed();
//set scroll limits
// setScrollParams(scrollX1, scrollY1, scrollX2, scrollY2);
//centre view
centreViewPos(centreX, centreY);
//more flexible alliance system
createAlliance(player, alliancePlayer);
count = 0;
while (count < numEnemies)
{
createAlliance(enemy[count], allianceEnemy[count]);
count = count + 1;
}
//set radar zoom level
setRadarZoom(zoomLevel);
//set LZ and no go areas - HAS to be done BEFORE FlyTransportersIn
initAllNoGoAreas();
count = 0;
while (count < numLZ)
{
setNoGoArea(LZX[count] - 1, LZY[count] - 1, LZX[count] + 1, LZY[count] + 1, count);
count = count + 1;
}
//call in transport
flyTransporterIn(player, transX[0], transY[0], false);
setTransporterExit(player, transX[1], transY[1]);
//set enemy transports if applicable
count = 0;
while (count < numEnemies)
{
if (entryX[count] != 0) //use entry exit as flag for need enemy transports
{
transportDroid[count] = addDroidToMissionList(transporter, enemy[count]);
}
count = count + 1;
}
//transGroupPlayer = 1; //make sure not 0!! since will control player's units
if (timeLimit != 0) //to cope with map expansions after sub maps!!!
{
setMissionTime(timeLimit);
}
//set transport time
if (not reinfOff)
{
setReinforcementTime(ReinforceTime);
}
//set structure limits
count = 0;
while (count < numStrucStats)
{
setStructureLimits (strucStat[count], strucLimit[count], player);
enableStructure(strucStat[count], player);
count = count + 1;
}
//set power levels
count = 0;
while (count < numEnemies)
{
//also set technology for each enemy
count2 = 0;
while (count2 < numTechs[count])
{
completeResearch(startTech[count][count2], enemy[count]);
count2 = count2 + 1;
}
setPowerLevel(power[count], enemy[count]);
count = count + 1;
}
//show player start objectives
count = 0;
while (count < numObjectives)
{
addMessage(objective[count], PROX_MSG, player, false);
count = count + 1;
}
//disable time fail if desired
if (noTimeLimit)
{
setEventTrigger(timeUp, inactive);
}
//Setup Artifacts already on map (NOT TESTED YET!)
//setting flags incorrectly in VLO could break game!
count = 0;
while (count < numArt)
{
if (artType[count] >= 4) //deal with no object to get artifact from
{ //eg for extra topics given at the end?
artFlag[count] = 4;
}
if (artType[count] == 0) //deal with artifact already on map
{
artID[count] = features[artVal[count]];
artFlag[count] = 1;
}
count = count + 1;
}
//setup enemy players health retreat settings
count = 0;
while (count < numEnemies)
{
if (healthRetreat[count] > 0)
{
setRetreatHealth(enemy[count], healthRetreat[count]);
setRetreatPoint(enemy[count], healthRetreatX[count], healthRetreatY[count]);
}
count = count + 1;
}
//setup groups
count = 0;
while (count < numGroups)
{
if (grpRegion[count] >= 0)
{
groupAddArea(grpGroup[count], enemy[grpPlayer[count]], regionsX1[grpRegion[count]], regionsY1[grpRegion[count]],
regionsX2[grpRegion[count]], regionsY2[grpRegion[count]]);
}
grpPosCurrent[count] = grpPosStart[count];
//set morale levels
if (grpMorale[count] >= 0)
{
/*
//set repair for now (run away not good enough!?)
setGroupSecondary(grpGroup[count], DSO_REPAIR_LEVEL, DSS_REPLEV_HIGH);
*/
//to get hill attackers to work properly
//setGroupSecondary(grpGroup[count], DSO_ATTACK_RANGE, DSS_ARANGE_LONG);
setGroupRetreatForce(grpGroup[count], grpMorale[count]);
setGroupRetreatLeadership(grpGroup[count], grpLeadership[count]);
if (grpType[count] < 2) //use coords for patrol/ambush/defence
{
setGroupRetreatPoint(grpGroup[count], coordsX[grpRetreatXY[count]], coordsY[grpRetreatXY[count]]);
}
else //use sectors for scout/attack
{
temp = grpRetreatXY[count];
//order scout/attack forces to random position in this sector
tempX = sectorsX1[temp] + random(sectorsX2[temp] - sectorsX1[temp]);
tempY = sectorsY1[temp] + random(sectorsY2[temp] - sectorsY1[temp]);
setGroupRetreatPoint(grpGroup[count], tempX, tempY);
}
}
//set time = 0 groups going
if (grpTimeGo[count] == timeGroup)
{
grpFlagGo[count] = TRUE;
if (grpType[count] < 2) //use coords for patrol/ambush/defence
{
if (grpPosStart[count] >= 0) //cope with no start position defined
{
orderGroupLoc(grpGroup[count], DORDER_SCOUT, coordsX[grpPosStart[count]], coordsY[grpPosStart[count]]);
}
}
else
{
temp = grpPosCurrent[count];
//order scout/attack forces to random position in this sector
tempX = sectorsX1[temp] + random(sectorsX2[temp] - sectorsX1[temp]);
tempY = sectorsY1[temp] + random(sectorsY2[temp] - sectorsY1[temp]);
orderGroupLoc(grpGroup[count], DORDER_SCOUT, tempX, tempY); //changed to SCOUT 21/01/99
}
}
//link to sensors for IDF groups (same index!)
if (grpType[count] == -1)
{
orderGroupObj(grpGroup[count], DORDER_FIRESUPPORT, droids[count]);
}
count = count + 1;
}
//set time = 0 factories going
count = 0;
while (count < numFactories)
{
//set assembly points, if desired
if ((factAssXY[count] != -1) and (factID[count] >= 0))
{
setAssemblyPoint (structures[factID[count]], coordsX[factAssXY[count]], coordsY[factAssXY[count]]);
}
if ((factTimeGo[count] == timeGroup) and (not factFlagGo[count]))
{
factFlagGo[count] = TRUE; //set factory to produce
}
count = count + 1;
}
//NEW! use trucks given as droids for each enemy
//Now done after groups set up so can pull them out of existing groups if necessary!
if (trucksOn)
{
//playSound(lostSnd, player); //test
count = 0;
while (count < numEnemies)
{
initGetFeature(oilRes, enemy[count], enemy[count]); // setup oil resource search for each enemy, so doesn't screw up!
count = count + 1;
}
count = 0;
while (droids[count] != NULLOBJECT)
{
if (droids[count].droidType == DROID_CONSTRUCT)
{
//found truck, now find owner
count2 = 0;
while (count2 < numEnemies)
{
if (droids[count].player == enemy[count2])
{
groupAddDroid(truckGroup[count2], droids[count]);
}
count2 = count2 + 1;
}
}
count = count + 1;
}
setEventTrigger (checkTrucks, checkTrucksTrig);
}
//END of find trucks
//allow win/lose checks
setEventTrigger(wonYetEvnt, winTrig);
setEventTrigger(lostYetEvnt, lostTrig);
//allow LZ compromised checks;
if (ReinforceTime < 0)
{
setEventTrigger(LZNoGo,inactive); //disable checks
}
//default LZRange
if (LZRange == 0)
{
LZRange = 768; //6 tiles radius if not specified
}
//play any video requirements before the briefings
if (numVideos > 0)
{
playVideo(video[0], videoText[0]);
countVideos = 1;
//allow next video or next briefing
setEventTrigger(briefings, vidEndTrig);
}
else
{
//play mission brief(s)
if (numBriefs > 0)
{
if (briefVal[0] < 2) //cope with don't play immediately
{
addMessage(brief[0], MISS_MSG, 0, true);
setEventTrigger(briefings, vidEndTrig); //allow next one
}
else
{
addMessage(brief[0], MISS_MSG, 0, false);
if (countBriefs >= numBriefs) //last briefing?
{
setEventTrigger(briefings, inactive);
}
}
countBriefs = 1;
}
}
}
event briefings(inactive)
{
//any more videos to play?
if (countVideos < numVideos)
{
playVideo(video[countVideos], videoText[countVideos]);
countVideos = countVideos + 1;
}
else
{
//move on to briefings
if (countBriefs > 0)
{
if (briefVal[countBriefs - 1] == 0) //check to see if needs removing
{
removeMessage(brief[countBriefs - 1], MISS_MSG, 0);
}
}
if (countBriefs >= numBriefs) //last briefing?
{
setEventTrigger(briefings, inactive);
}
if (countBriefs < numBriefs) //add next brief
{
if (briefVal[countBriefs] < 2) //cope with don't play immediately
{
addMessage(brief[countBriefs], MISS_MSG, 0, true);
}
else
{
addMessage(brief[countBriefs], MISS_MSG, 0, false);
}
countBriefs = countBriefs + 1;
}
}
}
/* Base Under Attack */
event baseHit(CALL_STRUCT_ATTACKED, selectedPlayer, ref hitStruc, ref attackerObj)
{
if (t >= 20)
{
t=0;
if (hitStruc != NULLOBJECT)
{
playSoundPos(attackSnd1, selectedPlayer, hitStruc.x, hitStruc.y, hitStruc.z); //show position if still alive
}
else
{
playSound(attackSnd1, selectedPlayer);
}
}
}
event everySec(every, 20) //update time delay before told again (about 20 seconds)
{
t=t+1;
}
/* Remove Objective Blips */
event removeObjectives(objTrig)
{
if (objectivesDone == numObjectives) //all blips gone?
{
setEventTrigger(removeObjectives, inactive);
}
else
{
count = 0;
while (count < numObjectives)
{
if ((not objectiveFlag[count]) and
(droidInRange(player, objectiveX[count], objectiveY[count], objectiveRange)))
{
objectiveFlag[count] = TRUE;
objectivesDone = objectivesDone + 1;
removeMessage(objective[count], PROX_MSG, player);
}
count = count + 1;
}
}
}
/* Artifacts */
//This works for artifacts from STRUCTURES, FEATURES or DROIDS as well as crates already on map!
//tested for STRUCTURES, FEATURES, DROIDS and starting CRATES
event artLoop(artTrig) //update artifact list
{
if (artCollected >= numArt) //all artifacts collected?
{
setEventTrigger(artLoop, inactive);
}
else
{
count = 0;
while (count < numArt)
{
if (artFlag[count] == 0)
{
temp = 0;
//might be a better way to do this check?
if (artType[count] == 1)
{
if (structures[artVal[count]] == NULLOBJECT) //from dead structure
{
temp = 1;
}
}
if (artType[count] == 2)
{
if (features[artVal[count]] == NULLOBJECT) //from dead feature
{
temp = 1;
}
}
if (artType[count] == 3)
{
if (droids[artVal[count]] == NULLOBJECT) //from dead droid
{
temp = 1;
}
}
if (temp == 1) //OK to place crate?
{
//place artifact crate, and allow check for prox
artID[count] = addFeature(crate, artX[count], artY[count]);
artFlag[count] = 1;
}
}
if (artFlag[count] == 1)
{
artFlag[count] = 2; //hack now don't need detected wav
}
if (artFlag[count] == 2)
{
if (droidInRange(player, artX[count], artY[count], artRange))
{
artCollected = artCollected + 1;
artFlag[count] = 3;
//playSound(artSnd2, player);
playSoundPos(artSnd2, player, artID[count].x, artID[count].y, artID[count].z);
destroyFeature(artID[count]);
//removeMessage(artMsg[count], PROX_MSG, player);
enableResearch(artComp[count], player);
}
}
if (artType[count] == 3)
{
if (droids[artVal[count]] != NULLOBJECT)
{
//keep track of droid position for crate when it dies
artX[count] = droids[artVal[count]].x;
artY[count] = droids[artVal[count]].y;
}
}
count = count + 1;
}
}
}
/* Enemy Base Blips */
event baseLoop(baseTrig) //update base blips
{
if (basesDead == numBases) //all bases gone?
{
setEventTrigger(baseLoop, inactive);
}
else
{
count = 0;
while (count < numBases)
{
if (baseFlag[count] == 0)
{
if (seenStructInArea(player, enemy[basePlayer[count]], FALSE,
regionsX1[baseRegion[count]], regionsY1[baseRegion[count]],
regionsX2[baseRegion[count]], regionsY2[baseRegion[count]]))
{
addMessage(baseMsg[count], PROX_MSG, player, false);
if (baseWav1[count] >= 0)
{
//playSound(baseSnd[baseWav1[count]], player);
//tricky one since don't have coords! Use middle of region??
playSoundPos(baseSnd[baseWav1[count]], player, (regionsX1[baseRegion[count]] + regionsX2[baseRegion[count]]) / 2,
(regionsY1[baseRegion[count]] + regionsY2[baseRegion[count]]) / 2, 0);
}
baseFlag[count] = 1;
}
}
if (baseFlag[count] == 1)
{
if (numStructsButNotWallsInArea(enemy[basePlayer[count]],
regionsX1[baseRegion[count]], regionsY1[baseRegion[count]],
regionsX2[baseRegion[count]], regionsY2[baseRegion[count]])== 0)
{
basesDead = basesDead + 1;
baseFlag[count] = 2;
if (baseWav2[count] >= 0)
{
//playSound(baseSnd[baseWav2[count]], player);
//tricky one since don't have coords! Use middle of region??
playSoundPos(baseSnd[baseWav2[count]], player, (regionsX1[baseRegion[count]] + regionsX2[baseRegion[count]]) / 2,
(regionsY1[baseRegion[count]] + regionsY2[baseRegion[count]]) / 2, 0);
}
removeMessage(baseMsg[count], PROX_MSG, player);
killStructsInArea(enemy[basePlayer[count]], REF_WALL, //remove walls and building features in base
regionsX1[baseRegion[count]], regionsY1[baseRegion[count]],
regionsX2[baseRegion[count]], regionsY2[baseRegion[count]],
TRUE, TRUE);
killStructsInArea(enemy[basePlayer[count]], REF_WALLCORNER, //remove corner walls in base
regionsX1[baseRegion[count]], regionsY1[baseRegion[count]],
regionsX2[baseRegion[count]], regionsY2[baseRegion[count]],
TRUE, FALSE);
}
}
count = count + 1;
}
}
}
/* Events: Win or Lose */
event nextLevEvnt(inactive) //assumes victory already checked
{
flushConsoleMessages();
pause(20); //increased to allow all audio before won
// give all research
count = 0;
while (count < numArt)
{
enableResearch(artComp[count], 0);
count = count +1;
}
//End game or next level
if (lastLev)
{
gameOver(true); //finished game
// Could call this instead with the message to play if thats what you want.
// gameOverMessage(winMsg, MISS_MSG, 0, true);
}
else
{
startMission(CAMP_EXPAND, NextLev); //load next level
}
setEventTrigger(nextLevEvnt, inactive);
}
//skip to end of level
event cheatEvnt(CALL_MISSION_START) //cheat button ctrl M
{
//special cheat destroys all enemy stuff
/* DONE IN CODE NOW!! (AT LEAST ON PSX)
count = 0;
while (count < numEnemies)
{
count2 = 0;
while (count2 < 20)
{
killStructsInArea(enemy[count], count2, scrollX1 * 128, scrollY1 * 128,
scrollX2 * 128, scrollY2 * 128, FALSE, FALSE );
count2 = count2 + 1;
}
//forceDamageObject(droids[0], 25);
//vanishUnit(droids[0]);
//
//remove enemy droids (no explosion)
groupAddArea(grpGroup[0], enemy[count], scrollX1 * 128, scrollY1 * 128,
scrollX2 * 128, scrollY2 * 128);
initIterateGroup(grpGroup[0]);
count2 = 0;
while (count2 < grpGroup[0].members)
{
droids[0] = iterateGroup(grpGroup[0]);
vanishUnit(droids[0]);
count2 = count2 + 1;
}
//
count = count + 1;
}
*/
//temporarily disable next level trigger, if need to check victory conditions
setEventTrigger(nextLevEvnt, nextLevTrig);
setEventTrigger(cheatEvnt, inactive);
}
event gameLost(inactive)
{
// addMessage(endMsg, MISS_MSG, 0, true);
// pause(10);
// gameOver(false);
gameOverMessage(endMsg, MISS_MSG, 0, false);
setEventTrigger(gameLost, inactive);
}
event lostYetEvnt(inactive) //triggered on (every, 25) now, set at end of start event
{
temp2 = 0; //stores number of conditions met
//all player stuff dead (ALWAYS LOSE!)
if ((not anyDroidsLeft(player)) and (not anyStructButWallsLeft(player)))
{
temp2 = 1;
}
//all group index fail[0] at region index fail[1]?
if ((fail[0] != -1) and (fail[1] != -1))
{
/* DON'T use group to check (use individual droid)
//now checks to see group not dead, and mid point is within region
if (grpGroup[fail[0]].members != 0)
{
if ((grpGroup[fail[0]].x > regionsX1[fail[1]]) and (grpGroup[fail[0]].x < regionsX2[fail[1]]) and
(grpGroup[fail[0]].y > regionsY1[fail[1]]) and (grpGroup[fail[0]].y < regionsY2[fail[1]]))
{
temp2 = 1;
}
}
*/
//now checks for a single droid referenced by fail[0] as index into droids[]
if (droids[fail[0]] != NULLOBJECT)
{
if ((droids[fail[0]].x > regionsX1[fail[1]]) and (droids[fail[0]].x < regionsX2[fail[1]]) and
(droids[fail[0]].y > regionsY1[fail[1]]) and (droids[fail[0]].y < regionsY2[fail[1]]))
{
playSound(failSnd, player); //let player know!
addConsoleText(failMsg, player); //text version
temp2 = 1;
}
}
}
/* might not need? NOT TESTED!!!
//all units dead?
if ((fail[2] != -1) and (not anyDroidsLeft(player)))
{
temp2 = 1;
}
//all structures dead?
if ((fail[3] != -1) and (not anyStructButWallsLeft(player)))
{
temp2 = 1;
}
//certain structure gone????
*/
//cope with failure set in other scripts
if (linkFail and extraFailFlag)
{
temp2 = 1;
}
if (temp2 == 1)
{
setEventTrigger(wonYetEvnt,inactive);
setEventTrigger(timeUp, inactive);
setEventTrigger(gameLost, gameLostTrig); //waits 2 seconds before ending
//playSound(lostSnd,0);
setEventTrigger(lostYetEvnt, inactive);
}
}
//out of time?
event timeUp(CALL_MISSION_TIME)
{
setEventTrigger(wonYetEvnt,inactive);
setEventTrigger(lostYetEvnt,inactive);
playSound(lostSnd,0); //may want different sound, eg "Out of Time"
setEventTrigger(gameLost, gameLostTrig); //waits 2 seconds before ending
setEventTrigger(timeUp, inactive);
}
event wonYetEvnt(inactive) //triggered on (artCollected >= victoryArt) set at end of start event
{
//check for extra victory conditions set in another script
if ((linkVictory and extraVictoryFlag) or (not linkVictory))
{
temp2 = 0; //stores number of conditions met
//needs to check various victory conditions setup in VLO
//check all enemy vehicles and structures destroyed
if (victory[0] != -1)
{
count = 0;
temp = 0;
while (count < numEnemies)
{
if ((not anyDroidsLeft(enemy[count]))
and (not anyStructButWallsLeft(enemy[count])))
{
temp = temp + 1;
}
count = count + 1;
}
if (temp == numEnemies)
{
temp2 = temp2 + 1;
}
}
//check number of objectives reached
if (victory[2] != -1)
{
count = 0;
temp = 0;
while (count < victory[2]) //check from objective 0 to #
{
if (objectiveFlag[count])
{
temp = temp + 1;
}
count = count + 1;
}
if (temp >= victory[2])
{
temp2 = temp2 + 1;
}
}
//check number of bases destroyed
if (victory[3] != -1)
{
count = 0;
temp = 0;
while (count < victory[3]) //check from base 0 to #
{
if (baseFlag[count] == 2)
{
temp = temp + 1;
}
count = count + 1;
}
if (temp >= victory[3])
{
temp2 = temp2 + 1;
}
}
//check ALL player vehicles in specific REGION (eg LZ)
if (victory[1] != -1)
{
//temp = numDroidsInArea(player, scrollX1 * 128, scrollY1 * 128, scrollX2 * 128, scrollY2 * 128);
temp = 1 + (9 * getDroidCount(player) / 10); //tot number of droids for player on map (NOW 90%!!)
if (temp <= numDroidsInArea(player, regionsX1[victory[1]],
regionsY1[victory[1]], regionsX2[victory[1]], regionsY2[victory[1]]))
{
if (temp != 0)
{
temp2 = temp2 + 1;
}
}
else if ((retLZFlag) and (temp2 == numVictory - 1)) //if getting to region is last victory, give sound and blip
{
retLZFlag = FALSE; //turn off checks
// playSound(retLZSnd, player); //tell player to return
addMessage(retLZBlip, PROX_MSG, player, false); //give LZ blip
// addConsoleText(retLZMsg, player);
setEventTrigger(periodicRTLZ,RTLZStart);
}
}
//next check goes here!
//now check if number of victory conditions met
if (temp2 == numVictory) //victory reached?
{
setEventTrigger(lostYetEvnt, inactive);
setEventTrigger(timeUp, inactive);
setEventTrigger(nextLevEvnt, nextLevTrig);
setEventTrigger(wonYetEvnt, inactive);
}
}
}
event periodicRTLZ(inactive)
{
playSound(retLZSnd, player); //tell player to return
showConsoleText(retLZMsg, player);
setEventTrigger(periodicRTLZ,RTLZFreq);
}
/* Enemy AI */
event wayGroups(wayGroupsTrig)
{
count = 0;
while (count < numGroups)
{
//update groups position
if ((grpFlagGo[count]) and (grpType[count] < 2) and (grpPosStart[count] >= 0)) //been triggered and ambush/patrol/defence?
{
//simple predefined waypoints
//has the group got to waypoint or are they mainly idle?
if ((grpGroup[count].members > 0) and ((grpGroup[count].health * grpGroup[count].members >= healthRetreat[grpPlayer[count]] + ((grpGroup[count].members - 1) * 100))
or (healthRetreat[grpPlayer[count]] == 0)) and (idleGroup(grpGroup[count]) >= grpGroup[count].members/2))
{
grpBusy[count] = FALSE; //no longer 'busy'
temp = grpPosCurrent[count]; //store for checking difference later
if (grpPosType[count] == 3) //random choice
{
grpPosCurrent[count] = grpPosMin[count] + grpPosStep[count] * random(grpPosMax[count] - grpPosMin[count]);
}
else
{
grpPosCurrent[count] = grpPosCurrent[count] + grpPosStep[count]; //get next waypoint
}
if ((grpPosCurrent[count] > grpPosMax[count]) or (grpPosCurrent[count] < grpPosMin[count]))
{
grpPosCurrent[count] = grpPosCurrent[count] - grpPosStep[count]; //stop at last one
if (grpPosType[count] == 1) //loop
{
if (grpPosStep[count] > 0) //+ve loop
{
grpPosCurrent[count] = grpPosMin[count];
}
else //-ve loop
{
grpPosCurrent[count] = grpPosMax[count];
}
}
if (grpPosType[count] == 2) //ping pong
{
grpPosStep[count] = - grpPosStep[count];
grpPosCurrent[count] = grpPosCurrent[count] + grpPosStep[count];
}
}
if (grpPosCurrent[count] != temp) //don't order again if already there!
{
orderGroupLoc(grpGroup[count], DORDER_SCOUT, coordsX[grpPosCurrent[count]], coordsY[grpPosCurrent[count]]); //Changed to SCOUT 21/01/99
//orderGroupLoc(grpGroup[count], DORDER_MOVE, coordsX[grpPosCurrent[count]], coordsY[grpPosCurrent[count]]);
}
}
}
count = count + 1;
}
}
/* THREAT ANALYSIS */
event threatGroups(threatGroupsTrig)
{
//traceOn();
count = 0;
while (count < numGroups)
{
if (grpMorale[count] > 0)
{
/*
temp1 = getThreatInArea(enemy[grpPlayer[count]], player, grpGroup[count].x - threatRange, grpGroup[count].y - threatRange, grpGroup[count].x + threatRange, grpGroup[count].y + threatRange, 0, 0, threatHeavy, TRUE);
temp2 = getThreatInArea(player, enemy[grpPlayer[count]], grpGroup[count].x - threatRange, grpGroup[count].y - threatRange, grpGroup[count].x + threatRange, grpGroup[count].y + threatRange, 0, 0, threatHeavy, TRUE);
*/
temp1 = getThreatInArea(enemy[grpPlayer[count]], player, grpGroup[count].x - threatRange, grpGroup[count].y - threatRange,
grpGroup[count].x + threatRange, grpGroup[count].y + threatRange, threatLight, threatMedium, threatHeavy, TRUE);
temp2 = getThreatInArea(player, enemy[grpPlayer[count]], grpGroup[count].x - threatRange, grpGroup[count].y - threatRange, grpGroup[count].x + threatRange, grpGroup[count].y + threatRange, threatLight, threatMedium, threatHeavy, FALSE);
if (temp1 > temp2) //does player have bigger looking force than me?
{
//playSound(lostSnd,0); //test
initIterateGroup(grpGroup[count]);
testDroid = iterateGroup(grpGroup[count]);
//must check to see if group not empty!
if (testDroid != NULLOBJECT)
{
orderDroid(testDroid, DORDER_RUN); //only need to order one (rest should follow?)
}
}
}
count = count + 1;
}
//traceOff();
}
/* SCOUTS AND TARGET FINDING */
event checkGroups(checkGroupsTrig)
{
count = 0;
while (count < numGroups)
{
initIterateGroup(grpGroup[count]);
count2 = 0;
while (count2 < grpGroup[count].members)
{
//check for morale failed, and make retreat fully
testDroid = iterateGroup(grpGroup[count]);
if ((testDroid.order == DORDER_RUN) and (not runOffFlag))
{
if (grpType[count] >= 2) //scout and attack type uses sectors
{
grpPosCurrent[count] = grpRetreatXY[count]; //flag retreat sector as current?
temp = grpRetreatXY[count];
//order scout forces to random position in this sector
tempX = sectorsX1[temp] + random(sectorsX2[temp] - sectorsX1[temp]);
tempY = sectorsY1[temp] + random(sectorsY2[temp] - sectorsY1[temp]);
orderGroupLoc(grpGroup[count], DORDER_MOVE, tempX, tempY);
}
else
{
orderGroupLoc(grpGroup[count], DORDER_MOVE, coordsX[grpRetreatXY[count]], coordsY[grpRetreatXY[count]]);
/* No longer allow groups that STOP at last waypoint to continue once retreated
if ((grpPosType[count] == 0)) // and (grpPosStart[count] != grpPosCurrent[count])) //stop and not 1st waypoint
{
//need to mark that current waypoint not yet reached for STOP type
grpPosCurrent[count] = grpPosCurrent[count] - grpPosStep[count]; //back to last one
}
*/
}
grpBusy[count] = TRUE; //mark busy (will become idle when at retreat point)
count2 = grpGroup[count].members; //exit loop
}
count2 = count2 + 1;
}
count = count + 1;
}
}
// not finished yet! Now includes attack groups as well as scout groups
event sectorGroups(sectorGroupsTrig)
{
count = 0;
while (count < numGroups)
{
if ((grpFlagGo[count]) and (grpType[count] >= 2) and (grpGroup[count].members > 0) //set going and scout/attack type only
and ((grpGroup[count].health * grpGroup[count].members >= healthRetreat[grpPlayer[count]] + ((grpGroup[count].members - 1) * 100))
or (healthRetreat[grpPlayer[count]] == 0)) //health OK (Cam3 NEXUS)
and (idleGroup(grpGroup[count]) >= (grpGroup[count].members / 2))) //also not busy!
{
grpBusy[count] = FALSE; //no longer 'busy'?
//attack group stuff
temp1 = 0; //just in case don't find an enemy match
if ((allianceFlag)) // and (random(numEnemies + 1) < 1))
{
temp1 = random(numEnemies); //allow allies targets as well!
}
else
{
// grpPlayer[count] is now index to enemy[], so no need to check
temp1 = grpPlayer[count];
}
if ((grpType[count] == 3) and (targetCount[temp1] > 0)) //any targets for attack groups
{
//new targetting system
//find a target in nearby vicinity
resetStructTargets();
if (random(100) < 10)
{
setStructTarPref(ST_WALL); //pick walls occassionally
}
hitStruc = structTargetInArea(player, grpPlayer[count], grpGroup[count].x - targetRange, grpGroup[count].y - targetRange,
grpGroup[count].x + targetRange, grpGroup[count].y + targetRange);
if (hitStruc != NULLOBJECT)
{
orderGroupObj(grpGroup[count], DORDER_ATTACK, hitStruc);
}
else //go to new target
{
temp2 = random(targetCount[temp1]);
orderGroupLoc(grpGroup[count], DORDER_SCOUT, targetX[temp1][temp2], targetY[temp1][temp2]);
}
}
else //otherwise next sector
{
//scout/next sector stuff
temp = grpPosCurrent[count]; //current scout sector
//10% chance of scouting past an occupied sector (even if valid targets exist there!)
//put in temp1 and temp2 for legibility!
temp1 = numStructsButNotWallsInArea(player, sectorsX1[temp], sectorsY1[temp], sectorsX2[temp], sectorsY2[temp]);
temp2 = numDroidsInArea(player, sectorsX1[temp], sectorsY1[temp], sectorsX2[temp], sectorsY2[temp]);
//next sector if clear of droids and structures or 10% chance
if ((random(100) < 10) or ((temp1 == 0) and (temp2 ==0)))
{
//sector clear so use as a retreat point 50% chance
if (random(100) < 50)
{
grpRetreatXY[count] = grpPosCurrent[count];
}
//get new sector (like wayGroups above!)
if (grpPosType[count] == 3) //random choice
{
grpPosCurrent[count] = grpPosMin[count] + grpPosStep[count] * random(grpPosMax[count] - grpPosMin[count]);
}
else
{
grpPosCurrent[count] = grpPosCurrent[count] + grpPosStep[count]; //get next waypoint
}
if ((grpPosCurrent[count] > grpPosMax[count]) or (grpPosCurrent[count] < grpPosMin[count]))
{
grpPosCurrent[count] = grpPosCurrent[count] - grpPosStep[count]; //stop at last one
if (grpPosType[count] == 1) //loop
{
if (grpPosStep[count] > 0) //+ve loop
{
grpPosCurrent[count] = grpPosMin[count];
}
else //-ve loop
{
grpPosCurrent[count] = grpPosMax[count];
}
}
if (grpPosType[count] == 2) //ping pong
{
grpPosStep[count] = - grpPosStep[count];
grpPosCurrent[count] = grpPosCurrent[count] + grpPosStep[count];
}
}
//playSound(lostSnd,0); //test
//now order to new sector
temp = grpPosCurrent[count];
//order scout forces to random position in this sector
tempX = sectorsX1[temp] + random(sectorsX2[temp] - sectorsX1[temp]);
tempY = sectorsY1[temp] + random(sectorsY2[temp] - sectorsY1[temp]);
orderGroupLoc(grpGroup[count], DORDER_SCOUT, tempX, tempY); //why was this on DORDER_MOVE?
}
}
}
count = count + 1;
}
}
//not finished yet!
event targetGroups(targetGroupsTrig)
{
//clear targets if any gone (by shuffling down array)
count = 0;
while (count < numEnemies)
{
if (targetCount[count] > 0)
{
temp = 0;
while (temp < targetCount[count])
{
/* OLD SYSTEM
if (numStructsButNotWallsInArea(player, targetX[count][temp] - targetRange, targetY[count][temp] - targetRange,
targetX[count][temp] + targetRange, targetY[count][temp] + targetRange) == 0)
//(not (objectInRange(player, targetX[count][temp], targetY[count][temp], targetRange)))
*/
//New system
//find a target in area
resetStructTargets();
setStructTarPref(ST_WALL); //include walls always
hitStruc = structTargetInArea(player, grpPlayer[count], targetX[count][temp] - targetRange, targetY[count][temp] - targetRange,
targetX[count][temp] + targetRange, targetY[count][temp] + targetRange);
if (hitStruc == NULLOBJECT)
{
count2 = temp;
while (count2 < targetCount[count])
{
targetX[count][count2] = targetX[count][count2 + 1];
targetY[count][count2] = targetY[count][count2 + 1];
count2 = count2 + 1;
}
targetCount[count] = targetCount[count] - 1; //reduce total for this enemy
}
temp = temp + 1;
}
}
//flag new targets, if any (structures and droids but not walls!), at the moment for any group (not just scouts)
count2 = 0;
while (count2 < numGroups)
{
temp1 = numStructsButNotWallsInArea(player, grpGroup[count2].x - targetRange, grpGroup[count2].y - targetRange,
grpGroup[count2].x + targetRange, grpGroup[count2].y + targetRange);
temp2 = numDroidsInArea(player, grpGroup[count2].x - targetRange, grpGroup[count2].y - targetRange,
grpGroup[count2].x + targetRange, grpGroup[count2].y + targetRange);
/* OLD SYSTEM
//make sure correct player, and targets exist before logging a new one
if ((grpPlayer[count2] == count) and (targetCount[count] < targetMax) and ((temp1 > 0) or (temp2 > 0)))
//(objectInRange(player, grpGroup[count2].x, grpGroup[count2].y, targetRange)))
*/
//New System
//find a target in area
resetStructTargets();
if (random(100) < 10)
{
setStructTarPref(ST_WALL); //pick walls occassionally
}
hitStruc = structTargetInArea(player, grpPlayer[count2], grpGroup[count2].x - targetRange, grpGroup[count2].y - targetRange,
grpGroup[count2].x + targetRange, grpGroup[count2].y + targetRange);
if ((targetCount[count] < targetMax) and (hitStruc != NULLOBJECT))
{
//playSound(lostSnd,1);
targetX[count][targetCount[count]] = grpGroup[count2].x;
targetY[count][targetCount[count]] = grpGroup[count2].y;
//order group to attack! (should be following heavies)
//orderGroupLoc(grpGroup[count2], DORDER_SCOUT, targetX[count][targetCount[count]], targetY[count][targetCount[count]]);
//if more objects than scouts, run away!!!
//if ((grpGroup[count2].members <= temp1 + temp2) and (grpType[count2] == 2))
//new way of running away (should be checking threat, but not yet)
temp = numDroidsInArea(enemy[grpPlayer[count2]], grpGroup[count2].x - targetRange, grpGroup[count2].y - targetRange,
grpGroup[count2].x + targetRange, grpGroup[count2].y + targetRange);
if ((temp <= temp1 + temp2) and (grpType[count2] == 2) and (grpMorale[count2] > 0))
{
//playSound(lostSnd,0); //test!
//use retreat stuff instead
orderGroup(grpGroup[count2], DORDER_RUN); //run away for a bit (will only work with initial retreat pos?)
}
else if ((grpType[count2] == 2) and ((idleGroup(grpGroup[count2]) >= grpGroup[count2].members / 2) or (random(100) < 5))) //only if not busy or small chance
{
//orderGroup(grpGroup[count2], DORDER_STOP); //stay where you are (and hopefully kill stuff) if scout group
orderGroupObj(grpGroup[count2], DORDER_ATTACK, hitStruc);
}
targetCount[count] = targetCount[count] +1;
}
count2 = count2 +1;
}
count = count +1;
}
}
event factoryProdEvnt(factoryProdTrig)
{
count = 0;
while (count < numFactories)
{
//switched on?
if (factFlagGo[count])
{
factTime[count] = factTime[count] + 1;
//time to do stuff?
if (factTime[count] >= factEvery[count])
{
//factTime[count] = 0; //now only done if can actually produce
//normal factory?
if (factID[count] >= 0)
{
//turn off dead factories
if (structures[factID[count]] == NULLOBJECT)
{
factFlagGo[count] = FALSE;
factEvery[count] = 32767; //make next time very large ~100 hours
}
//not producing anything?
else if (structureIdle(structures[factID[count]]))
{
//need to update template with technology!
//use min and max to get random build template
temp = random(factTempMax[count] - factTempMin[count]) + factTempMin[count];
temp2 = random(factTempMax[count] - temp) + 1; //build random number (less for better stuff)
buildDroid (templates[temp], structures[factID[count]], structures[factID[count]].player, temp2);
factTime[count] = 0; //reset time count
}
}
//phantom factory (including transports)
else if (factID[count] < 0)
{
//do actual adding of droids and resetting of FactTime in droidBuilt event
//just set trigger and factory number here!
newDroidFactoryIndex = count;
newDroid = NULLOBJECT;
newDroidFactory = NULLOBJECT; //so as not to confuse with a proper factory!
setEventTrigger(droidBuilt, droidBuiltTrig);
}
}
}
count = count + 1;
}
}
event droidBuilt(inactive) //triggered by later callbacks
{
//find factory number
temp2 = 0; //flagged if group match found
//temp = -1; //in case not found
temp = -2; //in case not found (so doesn't use a droidfactory from another script)
if (newDroidFactory != NULLOBJECT)
{
newDroidFactoryIndex = - 1; //not a phantom factory
count = 0;
while (count < numFactories)
{
if (factID[count] >= 0)
{
if (newDroidFactory == structures[factID[count]])
{
//this one wrong????
//temp = factID[count]; //count; //use factory index, not structure index
temp = count; //use factory index, not structure index
}
}
count = count +1;
}
}
else if (newDroidFactoryIndex >= 0) //deal with phantom factory
{
temp = newDroidFactoryIndex;
}
//check thru groups to reinforce
count = 0;
//cope with trucks being built
if (newDroid != NULLOBJECT) //don't bother if phantom factory
{
if (newDroid.droidType == DROID_CONSTRUCT)
{
count2 = 0;
while (count2 < numEnemies)
{
if (newDroid.player == enemy[count2])
{
groupAddDroid(truckGroup[count2], newDroid);
}
count2 = count2 + 1;
}
count = numGroups; //skip next bit!
}
//cope with sensors being built and IDF groups existing
else if (newDroid.droidType == DROID_SENSOR)
{
//now find 1st dead sensor droid slot that corresponds to an IDF group
count2 = 0;
while (count2 < numGroups)
{
if (grpType[count2] == -1)
{
//found an IDF group
if (droids[count2] == NULLOBJECT)
{
droids[count2] = newDroid;
orderGroupObj(grpGroup[count2], DORDER_FIRESUPPORT, droids[count2]);
count2 = numGroups; //end search
}
}
count2 = count2 + 1;
}
//count = numGroups; //Don't skip next bit! (needs to go into a group, unlike Trucks!)
}
}
//end of trucks bit
while (count < numGroups)
{
if (((temp == grpFactory[count]) or ((grpFactory[count] == -1) and (temp != -2))) //got match, or any factory in this script OK?
and (grpGroup[count].members < grpIdealSize[count])) //and needs reinforcing?
{
//add to reinforcement group
if (newDroid != NULLOBJECT)
{
groupAddDroid(grpReinforce[count], newDroid);
}
else if (newDroidFactoryIndex >= 0) //deal with phantom factory
{
//deal with off edge
if (factID[newDroidFactoryIndex] == - 1)
{
factTime[newDroidFactoryIndex] = 0; //reset time count for phantom factory
count2 = 0;
while (count2 < 1 + factTempMax[newDroidFactoryIndex] - factTempMin[newDroidFactoryIndex])
{
temp1 = factTempMin[newDroidFactoryIndex] + count2;
temp2 = count2; //create more for lower template numbers, less for higher!
while (temp2 < 1 + factTempMax[newDroidFactoryIndex] - factTempMin[newDroidFactoryIndex])
{
newDroid = addDroid(templates[temp1], coordsX[factAssXY[newDroidFactoryIndex]], coordsY[factAssXY[newDroidFactoryIndex]], enemy[grpPlayer[count]]);
if (newDroid != NULLOBJECT)
{
//cope with trucks
if (newDroid.droidType == DROID_CONSTRUCT)
{
groupAddDroid(truckGroup[grpPlayer[count]], newDroid);
}
//cope with sensors
else if (newDroid.droidType == DROID_SENSOR)
{
//now find 1st dead sensor droid slot that corresponds to an IDF group
count3 = 0;
while (count3 < numGroups)
{
if (grpType[count3] == -1)
{
//found an IDF group
if (droids[count3] == NULLOBJECT)
{
droids[count3] = newDroid;
orderGroupObj(grpGroup[count3], DORDER_FIRESUPPORT, droids[count3]);
count3 = numGroups; //end search
}
}
count3 = count3 + 1;
}
groupAddDroid(grpReinforce[count], newDroid);
}
else
{
groupAddDroid(grpReinforce[count], newDroid);
}
}
temp2 = temp2 + 1;
}
count2 = count2 + 1;
}
}
//deal with transport if not on map
else if ((factID[newDroidFactoryIndex] == - 2) and (not transOnMap[grpPlayer[count]]))
{
factTime[newDroidFactoryIndex] = 0; //reset time count for phantom factory
//need to check LZ has defences, otherwise turn off this phantom factory
temp1 = factAssXY[newDroidFactoryIndex];
if (numStructsInArea(enemy[grpPlayer[count]], (LZX[temp1] - 4) * 128, (LZY[temp1] - 4) * 128,
(LZX[temp1] + 4) * 128, (LZY[temp1] + 4) * 128) == 0)
{
//playSound(lostSnd, player); //test
factFlagGo[newDroidFactoryIndex] = FALSE;
factEvery[newDroidFactoryIndex] = 32767; //make next time very large ~100 hours
}
else
{
setNoGoArea(LZX[factAssXY[newDroidFactoryIndex]] - 1,
LZY[factAssXY[newDroidFactoryIndex]] - 1,
LZX[factAssXY[newDroidFactoryIndex]] + 1,
LZY[factAssXY[newDroidFactoryIndex]] + 1,
enemy[grpPlayer[newDroidFactoryIndex]]);
//make sure got position in world coords of this LZ for playSound
enemyLZX = LZX[factAssXY[newDroidFactoryIndex]] * 128;
enemyLZY = LZY[factAssXY[newDroidFactoryIndex]] * 128;
count2 = 0;
while (count2 < 1 + factTempMax[newDroidFactoryIndex] - factTempMin[newDroidFactoryIndex])
{
temp1 = factTempMin[newDroidFactoryIndex] + count2;
temp2 = count2; //create more for lower template numbers, less for higher!
while (temp2 < 1 + factTempMax[newDroidFactoryIndex] - factTempMin[newDroidFactoryIndex])
{
newDroid = addDroidToMissionList(templates[temp1], enemy[grpPlayer[count]]);
if (newDroid != NULLOBJECT AND transportDroid[grpPlayer[count]] != NULLOBJECT)
{
addDroidToTransporter(transportDroid[grpPlayer[count]], newDroid);
}
temp2 = temp2 + 1;
}
count2 = count2 + 1;
}
//call in transport
setTransporterExit(enemy[grpPlayer[count]], exitX[grpPlayer[count]], exitY[grpPlayer[count]]);
flyTransporterIn(enemy[grpPlayer[count]], entryX[grpPlayer[count]], entryY[grpPlayer[count]], false);
transOnMap[grpPlayer[count]] = TRUE;
transGroupIndex[grpPlayer[count]] = count; //store for when transport lands
transGroupPlayer = grpPlayer[count]; //may mess up multiple enemies having transports?
setEventTrigger(transLanded, transLandedTrig);
setEventTrigger(transGone1, transGone1Trig);
}
}
}
//if group dead, add to group and reset starting sector?
if (grpGroup[count].members == 0)
{
groupAddGroup(grpGroup[count], grpReinforce[count]);
//set back to start sector...?
grpPosCurrent[count] = grpPosMin[count]; //go back to min sector if starting group from scratch
/* NEW to handle zero size groups at start with morale settings */
//set morale again so recalculates size!
if (grpMorale[count] >= 0)
{
setGroupRetreatForce(grpGroup[count], grpMorale[count]);
}
/* END of NEW */
}
//if ideal size, add to main group!
else if (((grpGroup[count].members + grpReinforce[count].members) >= grpIdealSize[count]) or
((grpReinforce[count].members) >= 8)) //hack to make edge factories work
{
groupAddGroup(grpGroup[count], grpReinforce[count]);
//grpPosCurrent[count] = grpPosMin[count]; //test for now so can see if added to group
}
//test order only!!!
//orderGroupLoc(grpGroup[count], DORDER_SCOUT, coordsX[grpPosCurrent[count]], coordsY[grpPosCurrent[count]]);
count = numGroups; //exit early
temp2 = 1;
}
count = count +1;
}
//if temp2 != 0, ie not assigned to a group, put in a special group for that player, and pull out if a group can take from any and
//needs reinforcing. (another event to check thru pooled group?)
//still to be done!
}
//hack to allow CALL_NEWDROID to work with unspecified enemy players!!!!
event droidBuilt1(CALL_NEWDROID, 1, ref newDroid, ref newDroidFactory)
{
newDroidFactoryIndex = - 1; //not a phantom factory
setEventTrigger(droidBuilt, droidBuiltTrig);
}
event droidBuilt2(CALL_NEWDROID, 2, ref newDroid, ref newDroidFactory)
{
newDroidFactoryIndex = - 1; //not a phantom factory
setEventTrigger(droidBuilt, droidBuiltTrig);
}
event droidBuilt3(CALL_NEWDROID, 3, ref newDroid, ref newDroidFactory)
{
newDroidFactoryIndex = - 1; //not a phantom factory
setEventTrigger(droidBuilt, droidBuiltTrig);
}
event droidBuilt4(CALL_NEWDROID, 4, ref newDroid, ref newDroidFactory)
{
newDroidFactoryIndex = - 1; //not a phantom factory
setEventTrigger(droidBuilt, droidBuiltTrig);
}
event droidBuilt5(CALL_NEWDROID, 5, ref newDroid, ref newDroidFactory)
{
newDroidFactoryIndex = - 1; //not a phantom factory
setEventTrigger(droidBuilt, droidBuiltTrig);
}
event droidBuilt6(CALL_NEWDROID, 6, ref newDroid, ref newDroidFactory)
{
newDroidFactoryIndex = - 1; //not a phantom factory
setEventTrigger(droidBuilt, droidBuiltTrig);
}
event droidBuilt7(CALL_NEWDROID, 7, ref newDroid, ref newDroidFactory)
{
newDroidFactoryIndex = - 1; //not a phantom factory
setEventTrigger(droidBuilt, droidBuiltTrig);
}
event transLanded(inactive) //trigger set when transport called
{
temp = transGroupIndex[transGroupPlayer]; //to make easier to read
//test sound for now
//playSound(transSnd, player); //Enemy Transport Landing
//need to look at enemy LZ???
playSoundPos(transSnd, player, enemyLZX, enemyLZY, 0);
//check for trucks in transGroup
initIterateGroup(transGroup);
newDroid = iterateGroup(transGroup);
while(newDroid != NULLOBJECT)
{
if (newDroid.droidType == DROID_CONSTRUCT)
{
groupAddDroid(truckGroup[transGroupPlayer], newDroid);
}
//check for sensors as well
else if (newDroid.droidType == DROID_SENSOR)
{
//now find 1st dead sensor droid slot that corresponds to an IDF group
count2 = 0;
while (count2 < numGroups)
{
if (grpType[count2] == -1)
{
//found an IDF group
if (droids[count2] == NULLOBJECT)
{
droids[count2] = newDroid;
orderGroupObj(grpGroup[count2], DORDER_FIRESUPPORT, droids[count2]);
count2 = numGroups; //end search
}
}
count2 = count2 + 1;
}
}
newDroid = iterateGroup(transGroup); //point to next one
}
//end of truck/sensor check
groupAddGroup(grpReinforce[temp], transGroup);
//might just want to add directly to grpGroup?
//if group dead, add to group and reset starting sector?
if (grpGroup[temp].members == 0)
{
grpPosCurrent[temp] = grpPosMin[temp]; //go back to min sector if starting group from scratch
if ((grpType[temp] < 2) and (grpPosStart[temp] >= 0)) //give first orders unless scouts, since use sectors, or no waypoints defined
{
orderGroupLoc(grpReinforce[temp], DORDER_SCOUT, coordsX[grpPosCurrent[temp]], coordsY[grpPosCurrent[temp]]);
}
groupAddGroup(grpGroup[temp], grpReinforce[temp]);
//set back to start sector...?
/* NEW to handle zero size groups at start with morale settings */
//set morale again so recalculates size!
if (grpMorale[temp] >= 0)
{
setGroupRetreatForce(grpGroup[temp], grpMorale[temp]);
}
/* END of NEW */
}
//if >= ideal size add to group
if ((grpGroup[temp].members + grpReinforce[temp].members) >= grpIdealSize[temp])
{
if ((grpType[temp] < 2) and (grpPosStart[temp] >= 0)) //give first orders unless scouts, since use sectors, or no waypoints defined
{
orderGroupLoc(grpReinforce[temp], DORDER_SCOUT, coordsX[grpPosCurrent[temp]], coordsY[grpPosCurrent[temp]]);
}
groupAddGroup(grpGroup[temp], grpReinforce[temp]);
}
setEventTrigger(transLanded, transLandedTrig);
}
//allow next transport!!
event transGone1(inactive)
{
transOnMap[grpPlayer[transGroupPlayer]] = FALSE;
}
event regionGroupsEvnt(regionGroupsTrig)
{
//check for groups
count = 0;
while (count < numGroups)
{
//region triggered? (NOT used if grpType = 1 (DEFENSIVE group). RegionGo defines area to defend instead!)
if ((not grpFlagGo[count]) and (grpType[count] != 1) and (grpRegionGo[count] >= 0))
{
if (droidInArea(grpWhoGo[count],
regionsX1[grpRegionGo[count]], regionsY1[grpRegionGo[count]],
regionsX2[grpRegionGo[count]], regionsY2[grpRegionGo[count]]))
{
grpFlagGo[count] = TRUE;
//scouts and attack forces don't use coords array, so don't bother with initial order!
if (grpType[count] < 2)
{
orderGroupLoc(grpGroup[count], DORDER_SCOUT, coordsX[grpPosStart[count]], coordsY[grpPosStart[count]]);
}
}
}
count = count + 1;
}
//check for factories
count = 0;
while (count < numFactories)
{
//region triggered?
if ((not factFlagGo[count]) and (factRegionGo[count] >= 0) and (factTime[count] == 0))
{
if (droidInArea(player, //assume Player to trigger region, rather than WhoGo[]
regionsX1[factRegionGo[count]], regionsY1[factRegionGo[count]],
regionsX2[factRegionGo[count]], regionsY2[factRegionGo[count]]))
{
factFlagGo[count] = TRUE;
factTime[count] = factEvery[count]; //allow to produce straight away!
}
}
count = count + 1;
}
}
//update time count for triggering groups and factories...
event timeGroupsEvnt(timeGroupsTrig)
{
timeGroup = timeGroup + 1;
count = 0;
//update groups
while (count < numGroups)
{
if ((grpTimeGo[count] == timeGroup) and (not grpFlagGo[count]))
{
grpFlagGo[count] = TRUE;
//scouts don't use coords array, so don't bother with initial order!
if (grpType[count] < 2)
{
orderGroupLoc(grpGroup[count], DORDER_SCOUT, coordsX[grpPosStart[count]], coordsY[grpPosStart[count]]);
}
}
count = count + 1;
}
//update factories
count = 0;
while (count < numFactories)
{
if ((factTimeGo[count] == timeGroup) and (not factFlagGo[count]) and (factTime[count] == 0))
{
factFlagGo[count] = TRUE; //set factory to produce
factTime[count] = factEvery[count]; //allow to produce straight away!
}
count = count + 1;
}
}
event enemyBaseHit(CALL_STRUCT_ATTACKED, enemy[enemyCount], ref hitStruc, ref attackerObj)
{
//playSound(attackSnd1, enemy[enemyCount]); //quick check
//store attacked structure for repairing by trucks later (when no enemies nearby!)
/* still to be done
if (hitStruc != NULLOBJECT)
{
//store damaged Structure for repair/rebuild later...
temp = 0;
count = 0;
while (count < numDamaged[enemyCount])
{
if
}
}
*/
if ((attackerObj != NULLOBJECT) and (hitStruc != NULLOBJECT))
{
count = 0;
while (count < numGroups)
{
//check for defense forces that cover this region
//but only if this structure belongs to same player as defensive group
//and isn't already 'busy'
if ((grpType[count] == 1) and (grpPlayer[count] == enemyCount) and (not grpBusy[count]))
{
if (grpRegionGo[count] < 0) //cope with no region specified
{
orderGroupLoc(grpGroup[count], DORDER_SCOUT, attackerObj.x, attackerObj.y);
grpBusy[count] = TRUE;
count = numGroups; //break out of loop, since found
}
else if ((hitStruc.x >= regionsX1[grpRegionGo[count]])
and (hitStruc.x <= regionsX2[grpRegionGo[count]])
and (hitStruc.y >= regionsY1[grpRegionGo[count]])
and (hitStruc.y <= regionsY2[grpRegionGo[count]]))
{
orderGroupLoc(grpGroup[count], DORDER_SCOUT, attackerObj.x, attackerObj.y);
grpBusy[count] = TRUE;
count = numGroups; //break out of loop, since found
}
}
count = count + 1;
}
}
}
//Updates enemyCount for enemyBaseHit event.
event updateEnemy(updateEnemyTrig)
{
/*
enemyCount = enemyCount + 1;
if (enemyCount >= numEnemies)
{
enemyCount = 0;
}
*/
//done this way so never invalid!
if (enemyCount < numEnemies - 1)
{
enemyCount = enemyCount + 1;
}
else
{
enemyCount = 0;
}
}
//NEW
//Make specified trucks (defined as droids[]) build derricks on visible oil resources
event buildDerrick(inactive) //only used if trucks found!
{
count = 0;
while (count < numEnemies)
{
feature = getFeature(enemy[count]); // find unoccupied oil resource that's been seen by this enemy
if(feature != NULLOBJECT)
{
initIterateGroup(truckGroup[count]); // find idle droids in build group.
testDroid = iterateGroup(truckGroup[count]);
while(testDroid != NULLOBJECT)
{
if ((testDroid.order == DORDER_NONE) or (testDroid.order == DORDER_RTB))
{
tempX = feature.x;
tempY = feature.y;
orderDroidStatsLoc(testDroid, DORDER_BUILD, strucStat[1], tempX, tempY); //build a derick
testDroid = NULLOBJECT;
}
else
{
testDroid = iterateGroup(truckGroup[count]);
}
}
}
else // feature is null
{
initGetFeature(oilRes, enemy[count], enemy[count]); // start again next time.
}
count = count + 1;
}
}
//build defences around nearby defenceless structures
event buildDefences(inactive) //only used if trucks found!
{
count = 0;
while (count < numEnemies)
{
initIterateGroup(truckGroup[count]); // find idle droids in build group.
testDroid = iterateGroup(truckGroup[count]);
while(testDroid != NULLOBJECT) //NB: need to be careful don't end up in endless loop!
{
if ((testDroid.order == DORDER_NONE) or (testDroid.order == DORDER_RTB))
{
//spare truck found, so check nearby for defendable structures
count2 = 0;
while (count2 < numToDefend) //list of structurestats to defend
{
hitStruc = structureBuiltInRange(toDefend[count2], testDroid.x, testDroid.y, truckRange, enemy[count]);
if (hitStruc != NULLOBJECT)
{
if ((numStructsByTypeInArea(enemy[count], REF_DEFENSE, hitStruc.x - defRange, hitStruc.y - defRange,
hitStruc.x + defRange, hitStruc.y + defRange) < maxDefence) and (numDefences > 0))
{
tempX = hitStruc.x;
tempY = hitStruc.y;
temp = random(numDefences);
boolResult = pickStructLocation(defences[temp], ref tempX, ref tempY, enemy[count]);
if (boolResult)
{
orderDroidStatsLoc(testDroid, DORDER_BUILD, defences[temp], tempX, tempY); //build a defence
testDroid = NULLOBJECT;
count2 = numToDefend; //break loops early
}
}
}
count2 = count2 + 1;
}
if ((testDroid != NULLOBJECT) and (random(100) < 50)) //go back to base if couldn't build
{
orderDroid(testDroid, DORDER_RTB); // return to base if failed
}
}
if (testDroid != NULLOBJECT) //get next if haven't broken out of loop
{
testDroid = iterateGroup(truckGroup[count]);
}
}
count = count + 1;
}
}
event checkTrucks(inactive) //can be whatever time necessary now!
{
//check for switching on trucks
if (not truckFlag)
{
count = 0;
while (count < numEnemies)
{
if (truckGroup[count].members > 0)
{
truckFlag = TRUE;
}
count = count + 1;
}
if (truckFlag)
{
setEventTrigger(buildDerrick, buildDerrickTrig);
setEventTrigger(buildDefences, buildDefencesTrig);
}
}
else
//check for switching off trucks
{
count = 0;
temp = 0;
while (count < numEnemies)
{
if (truckGroup[count].members == 0)
{
temp = temp + 1;
}
count = count + 1;
}
if (temp == numEnemies)
{
//playSound(lostSnd, player); //test
truckFlag = FALSE;
setEventTrigger(buildDerrick, inactive);
setEventTrigger(buildDefences, inactive);
}
}
}
/* Old system
event sensorTarget(every, 67)
{
//get some kind of target if there's a sensor droid listed
count = 0;
temp = 0;
while (droids[count] != NULLOBJECT)
{
if (droids[count].droidType == DROID_SENSOR)
{
temp = temp + 1;
if ((droids[count].order == DORDER_NONE) or (droids[count].order == DORDER_SCOUT))
{
//find target (use Structure limits StructureStats for now!!!!)
count2 = 0;
while (count2 < numStrucStats)
{
//use range of 1024 for now
hitStruc = structureBuiltInRange(strucStat[count2], droids[count].x, droids[count].y, 1024, player);
if (hitStruc != NULLOBJECT)
{
orderDroidObj(droids[count], DORDER_OBSERVE, hitStruc);
count2 = numStrucStats;
}
count2 = count2 + 1;
}
}
}
count = count + 1;
}
if (temp == 0)
{
setEventTrigger(sensorTarget, inactive);
}
}
*/
//Better way of doing this (will attack allsorts of things!
event sensorTarget(every, 67)
{
//get some kind of target if there's a sensor droid listed
count = 0;
while (droids[count] != NULLOBJECT)
{
if (droids[count].droidType == DROID_SENSOR)
{
if ((droids[count].order == DORDER_NONE) or (droids[count].order == DORDER_SCOUT))
{
//find a target in area
resetStructTargets();
if (random(100) < 10)
{
setStructTarPref(ST_WALL); //pick walls occassionally
}
hitStruc = structTargetInArea(player, droids[count].player, droids[count].x - 768, droids[count].y - 768, droids[count].x + 768, droids[count].y + 768);
if (hitStruc != NULLOBJECT)
{
orderDroidObj(droids[count], DORDER_OBSERVE, hitStruc);
}
}
}
count = count + 1;
}
}
/* LZ compromised stuff */
event LZNoGo(checkLZTrig)
{
temp = 0;
//check for compromised
count = 0;
while (count < numEnemies)
{
//if (objectInArea(enemy[count], (LZX[player] * 128) - LZRange, (LZY[player] * 128) - LZRange, (LZX[player] * 128) + LZRange, (LZY[player] * 128) + LZRange))
if (droidInRange(enemy[count], (LZX[player] * 128), (LZY[player] * 128), LZRange))
{
temp = temp + 1;
}
count = count + 1;
}
if ((not playerTransOnMap) and (temp > 0)) //make sure transport not already landing!
{
//check LZ area for enemy structures and/or vehicles (in Trigger)
//playSound(LZComp, player); //"LZ Compromised"
playSoundPos(LZComp, player, LZX[player] * 128, LZY[player] * 128, 0);
//disable transport landing
setReinforcementTime(LZ_COMPROMISED_TIME); //MAGIC NUMBER IN HERE!!!
//allow check for clear!
setEventTrigger(LZ_OK, checkLZTrig);
setEventTrigger(LZNoGo, inactive);
}
}
event LZ_OK(inactive)
{
temp = 0;
//check LZ area clear of enemy structures and/or vehicles (not in Trigger)
count = 0;
while (count < numEnemies)
{
//if (objectInArea(enemy[count], (LZX[player] * 128) - LZRange, (LZY[player] * 128) - LZRange, (LZX[player] * 128) + LZRange, (LZY[player] * 128) + LZRange))
if (droidInRange(enemy[count], (LZX[player] * 128), (LZY[player] * 128), LZRange))
{
temp = temp + 1;
}
count = count + 1;
}
if (temp == 0) //clear so do message
{
//playSound(LZClear, player); //"LZ Clear"
playSoundPos(LZClear, player, LZX[player] * 128, LZY[player] * 128, 0);
//allow reinforcements now LZ clear
setReinforcementTime(ReinforceTime); //(set back to normal)
setEventTrigger(LZNoGo, checkLZTrig);
setEventTrigger(LZ_OK, inactive);
}
}
event playerTransOn(CALL_TRANSPORTER_REINFORCE)
{
playerTransOnMap = TRUE;
}
event playerTransOff(CALL_TRANSPORTER_OFFMAP, player)
{
playerTransOnMap = FALSE;
}