2143 lines
65 KiB
Plaintext
2143 lines
65 KiB
Plaintext
//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;
|
|
}
|
|
|
|
|