Initial Commit
Initial Commit
This commit is contained in:
282
_module/nss/explo_onenter.nss
Normal file
282
_module/nss/explo_onenter.nss
Normal file
@@ -0,0 +1,282 @@
|
||||
#include "_sh_inc_list"
|
||||
#include "events_inc"
|
||||
|
||||
//A function to spawn enemies
|
||||
void SpawnRandomEnemies(object oPC, string sAreaString, int nEncounterType)
|
||||
{
|
||||
//Identify a region by the area string
|
||||
string sRegionString = GetStringLeft(sAreaString, 1);
|
||||
|
||||
//Get PC's level to determine enemies to spawn
|
||||
int nLevel = GetHitDice(oPC);
|
||||
|
||||
//Modify the level to spawn weaker enemies for encounters other than with a "mini-boss"
|
||||
if (nEncounterType != ENCOUNTER_TYPE_MINIBOSS)
|
||||
{
|
||||
if (nLevel == 1) nLevel = 0;
|
||||
else if (nLevel <= 3) nLevel = 1;
|
||||
else if (nLevel <= 20) nLevel = nLevel - 2;
|
||||
else nLevel = nLevel - 3;
|
||||
|
||||
//30% of the time (unless it's an encounter with a mini-boss) the PC will find weaker enemies
|
||||
if (Random(100) <= 29 && nLevel >= 4)
|
||||
{
|
||||
if (nLevel <= 20) nLevel = Random(nLevel-1);
|
||||
else nLevel = Random(21);
|
||||
}
|
||||
}
|
||||
|
||||
//Select possible enemies
|
||||
SelectEnemies(sRegionString, nLevel, oPC, nEncounterType);
|
||||
string sEnemy1 = GetLocalString(oPC, "sEnemy1");
|
||||
string sEnemy2 = GetLocalString(oPC, "sEnemy2");
|
||||
string sEnemy3 = GetLocalString(oPC, "sEnemy3");
|
||||
string sEnemy4 = GetLocalString(oPC, "sEnemy4");
|
||||
string sEnemy5 = GetLocalString(oPC, "sEnemy5");
|
||||
string sEnemy6 = GetLocalString(oPC, "sEnemy6");
|
||||
string sAdd1 = GetLocalString(oPC, "sAdd1");
|
||||
string sAdd2 = GetLocalString(oPC, "sAdd2");
|
||||
string sAdd3 = GetLocalString(oPC, "sAdd3");
|
||||
string sAdd4 = GetLocalString(oPC, "sAdd4");
|
||||
DeleteEnemyVar(oPC);
|
||||
|
||||
//Get the number of players in a party and spawn up to 5 times the number of enemies
|
||||
int nPlayers = 0;
|
||||
object oParty = GetFirstFactionMember(oPC);
|
||||
while (GetIsObjectValid(oParty))
|
||||
{
|
||||
nPlayers++;
|
||||
|
||||
//include henchmen in the count
|
||||
object oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oParty, 1);
|
||||
int k;
|
||||
for (k = 2; GetIsObjectValid(oAssociate); k++)
|
||||
{
|
||||
if (GetLocalInt(oAssociate, "HenchPosition") > 0) nPlayers++;
|
||||
oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oParty, k);
|
||||
}
|
||||
|
||||
oParty = GetNextFactionMember(oPC);
|
||||
}
|
||||
if (nPlayers > 5) nPlayers = 5;
|
||||
int j;
|
||||
|
||||
//Spawn 2 enemies for ENCOUNTER_TYPE_FEW, 3 for ENCOUNTER_TYPE_NORMAL and 4 for ENCOUNTER_TYPE_MANY if there are no adds
|
||||
location lWaypoint;
|
||||
string sWayTag;
|
||||
int nWayNumber;
|
||||
int i;
|
||||
object oCreature;
|
||||
if (sAdd1 == "")
|
||||
{
|
||||
//Spawning main enemies
|
||||
if (nEncounterType == ENCOUNTER_TYPE_FEW) nWayNumber = 2;
|
||||
if (nEncounterType == ENCOUNTER_TYPE_NORMAL) nWayNumber = 3;
|
||||
if (nEncounterType == ENCOUNTER_TYPE_MANY) nWayNumber = 4;
|
||||
if (nEncounterType == ENCOUNTER_TYPE_MINIBOSS) nWayNumber = 1;
|
||||
for (i = 1; i <= nWayNumber; i++)
|
||||
{
|
||||
sWayTag = "rand_wp_" + sAreaString + "_" + IntToString(i);
|
||||
lWaypoint = GetLocation(GetWaypointByTag(sWayTag));
|
||||
for (j = 1; j <= nPlayers; j++)
|
||||
{
|
||||
oCreature = CreateObject(OBJECT_TYPE_CREATURE, SelectMain(sEnemy1, sEnemy2, sEnemy3, sEnemy4, sEnemy5, sEnemy6), lWaypoint);
|
||||
ScaleCreature(oCreature, nLevel);
|
||||
AssignCommand(oCreature, ActionRandomWalk());
|
||||
}
|
||||
}
|
||||
}
|
||||
//Spawn 4 enemies (3 adds) for ENCOUNTER_TYPE_FEW, 5 (3 adds) for ENCOUNTER_TYPE_NORMAL and 6 (4 adds) for ENCOUNTER_TYPE_MANY if there are no adds
|
||||
else
|
||||
{
|
||||
//Spawning main enemies
|
||||
if (nEncounterType == ENCOUNTER_TYPE_FEW) nWayNumber = 1;
|
||||
if (nEncounterType == ENCOUNTER_TYPE_NORMAL) nWayNumber = 2;
|
||||
if (nEncounterType == ENCOUNTER_TYPE_MANY) nWayNumber = 2;
|
||||
if (nEncounterType == ENCOUNTER_TYPE_MINIBOSS) nWayNumber = 1;
|
||||
for (i = 1; i <= nWayNumber; i++)
|
||||
{
|
||||
sWayTag = "rand_wp_" + sAreaString + "_" + IntToString(i);
|
||||
lWaypoint = GetLocation(GetWaypointByTag(sWayTag));
|
||||
for (j = 1; j <= nPlayers; j++)
|
||||
{
|
||||
oCreature = CreateObject(OBJECT_TYPE_CREATURE, SelectMain(sEnemy1, sEnemy2, sEnemy3, sEnemy4, sEnemy5, sEnemy6), lWaypoint);
|
||||
AssignCommand(oCreature, ActionRandomWalk());
|
||||
}
|
||||
}
|
||||
|
||||
//Spawning adds
|
||||
if (nEncounterType == ENCOUNTER_TYPE_FEW) nWayNumber = i+3;
|
||||
if (nEncounterType == ENCOUNTER_TYPE_NORMAL) nWayNumber = i+3;
|
||||
if (nEncounterType == ENCOUNTER_TYPE_MANY) nWayNumber = i+4;
|
||||
if (nEncounterType == ENCOUNTER_TYPE_MINIBOSS) nWayNumber = 0;
|
||||
for (i = i; i <= nWayNumber; i++)
|
||||
{
|
||||
if (nWayNumber == 0) break; //Nothing to do here if it's a mini-boss encounter
|
||||
sWayTag = "rand_wp_" + sAreaString + "_" + IntToString(i);
|
||||
lWaypoint = GetLocation(GetWaypointByTag(sWayTag));
|
||||
for (j = 1; j <= nPlayers; j++)
|
||||
{
|
||||
oCreature = CreateObject(OBJECT_TYPE_CREATURE, SelectAdd(sAdd1, sAdd2, sAdd3, sAdd4), lWaypoint);
|
||||
AssignCommand(oCreature, ActionRandomWalk());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
//Let's set this area's pseudo OnExit event (as a workaround for players quitting the game)
|
||||
SetLocalString(OBJECT_SELF, "OnExit", "pseudo_onexit");
|
||||
|
||||
//A workaround to enable selecting this area in the OnClientLeave event, since GetArea returns OBJECT_INVALID there
|
||||
SetLocalObject(GetEnteringObject(), "StoredArea", OBJECT_SELF);
|
||||
|
||||
//A workaround to prevent the OnEnter event body from firing after loading a saved game
|
||||
if (GetLocalInt(GetModule(), "LoadCooldown") == TRUE) return;
|
||||
|
||||
//Get the area we're in from the area variable, get the PC and declare some variables
|
||||
string sAreaString = GetLocalString(OBJECT_SELF, "AreaString");
|
||||
object oPC = GetEnteringObject();
|
||||
int nEncounterType;
|
||||
|
||||
//Sanity check
|
||||
if (!GetIsPC(oPC)) return;
|
||||
|
||||
//Add to the counter of PCs in the area
|
||||
SetLocalInt(OBJECT_SELF, "Players", GetLocalInt(OBJECT_SELF, "Players")+1);
|
||||
//TEST
|
||||
//FloatingTextStringOnCreature(IntToString(GetLocalInt(OBJECT_SELF, "Players")), oPC);
|
||||
|
||||
//Determine whether a/chestvillage/dungeon should be possible to discover
|
||||
int nCanDiscover = GetLocalInt(oPC, "CanDiscover");
|
||||
|
||||
//Spawn an escorted client
|
||||
RetrieveClient(oPC);
|
||||
|
||||
//Do nothing if there is already another PC in the area (and the area integer is TRUE) or try a spot/listen check if an ambush is prepared
|
||||
if (GetLocalInt(OBJECT_SELF, "IsPopulated") == TRUE)
|
||||
{
|
||||
int nDC = GetLocalInt(OBJECT_SELF, "Level");
|
||||
|
||||
if (nDC == 0) return;
|
||||
|
||||
int nSkillRoll;
|
||||
string sString;
|
||||
nSkillRoll = GetSkillRank(SKILL_SPOT, oPC) + d20();
|
||||
if (nSkillRoll >= nDC) sString = "[Spot] Ambush detected!";
|
||||
else
|
||||
{
|
||||
nSkillRoll = GetSkillRank(SKILL_LISTEN, oPC) + d20();
|
||||
if (nSkillRoll >= nDC) sString = "[Listen] Ambush detected!";
|
||||
}
|
||||
FloatingTextStringOnCreature(sString, oPC, FALSE);
|
||||
WriteTimestampedLogEntry(GetName(oPC)+": populated, OnEnter stops"); //TEST
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//Otherwise flag this area as populated, so that no event is generated for next players entering it
|
||||
SetLocalInt(OBJECT_SELF, "IsPopulated", TRUE);
|
||||
|
||||
//Now select the leader of the entering party, stored earlied - we can delete this variable afterwards
|
||||
oPC = GetLocalObject(OBJECT_SELF, "PartyLeader");
|
||||
DeleteLocalObject(OBJECT_SELF, "PartyLeader");
|
||||
|
||||
//TEST
|
||||
//FloatingTextStringOnCreature(GetName(oPC), oPC);
|
||||
|
||||
//Delete this area from the list of free areas
|
||||
string sRegionString = GetStringLeft(sAreaString, 1);
|
||||
string sList = "sList"+sRegionString;
|
||||
object oList = GetLocalObject(GetModule(), sList);
|
||||
int i;
|
||||
for (i = 1; i <= ListGetElementCount(oList); i++)
|
||||
{
|
||||
if (ListGetString(oList, i) == sAreaString) ListRemoveElement(oList, i);
|
||||
}
|
||||
|
||||
//TEST
|
||||
for (i = 1; i <= ListGetElementCount(oList); i++)
|
||||
{
|
||||
WriteTimestampedLogEntry(GetName(oPC)+": "+ListGetString(oList, i));
|
||||
}
|
||||
|
||||
int nRandom = Random(100)+1;
|
||||
WriteTimestampedLogEntry("Area event number (1-25: nothing, 26-80: monsters, 81-100: event): "+IntToString(nRandom)); //TEST
|
||||
//FloatingTextStringOnCreature("Wylosowano: "+IntToString(nRandom), oPC); //TEST
|
||||
|
||||
//Spawn a random chest 5%+(players in party)*5% (max 25%) of the time on one of three chest waypoints (only if CanDiscover is TRUE)
|
||||
int nChestWaypoint;
|
||||
string sChestWaypoint;
|
||||
object oChestWp;
|
||||
int nPCs;
|
||||
object oPartyMember = GetFirstFactionMember(oPC, TRUE);
|
||||
while (oPartyMember != OBJECT_INVALID)
|
||||
{
|
||||
nPCs++;
|
||||
oPartyMember = GetNextFactionMember(oPC, TRUE);
|
||||
}
|
||||
int nPercentage = 5*nPCs+5;
|
||||
if (nPercentage >= 25) nPercentage = 25;
|
||||
int nTestRand = Random(100)+1;
|
||||
WriteTimestampedLogEntry("Chest: "+IntToString(nTestRand)+" | "+IntToString(nPercentage)); //TEST
|
||||
if (nTestRand <= nPercentage && nCanDiscover > 1)
|
||||
{
|
||||
WriteTimestampedLogEntry("Chest spawned"); //TEST
|
||||
nChestWaypoint = Random(3)+1;
|
||||
sChestWaypoint = IntToString(nChestWaypoint);
|
||||
oChestWp = GetWaypointByTag("chest_wp_"+sAreaString+"_"+sChestWaypoint);
|
||||
SpawnTreasureChest(oPC, oChestWp);
|
||||
}
|
||||
|
||||
//Determine whether a PC encounters a village/dungeon at the end of the area
|
||||
if (Random(10) == 0) SetLocalInt(OBJECT_SELF, "DiscoveredVillage", TRUE);
|
||||
if (nCanDiscover > 1)
|
||||
{
|
||||
if (Random(20) == 0) SetLocalInt(OBJECT_SELF, "DiscoveredDungeon", TRUE);
|
||||
}
|
||||
|
||||
//Nothing in particular happens 25% of the time
|
||||
if (nRandom <= 25) return;
|
||||
|
||||
//Regular enemies encountered 55% of the time
|
||||
if (nRandom <= 80)
|
||||
{
|
||||
nRandom = Random(100)+1;
|
||||
|
||||
//A single strong opponent is encountered 20% of the time
|
||||
if (nRandom <= 20) nEncounterType = ENCOUNTER_TYPE_MINIBOSS;
|
||||
|
||||
//A few regular enemies are encountered 20% of the time
|
||||
else if (nRandom <= 40) nEncounterType = ENCOUNTER_TYPE_FEW;
|
||||
|
||||
//Many regular enemies are encountered 20% of the time
|
||||
else if (nRandom <= 60) nEncounterType = ENCOUNTER_TYPE_MANY;
|
||||
|
||||
//An average number of regular enemies is encountered 40% of the time
|
||||
else nEncounterType = ENCOUNTER_TYPE_NORMAL;
|
||||
}
|
||||
|
||||
//An event occurs 20% of the time
|
||||
else
|
||||
{
|
||||
switch (Random(10))
|
||||
{
|
||||
case 0: SpawnNemesisEvent(oPC); break;
|
||||
case 1: SpawnEscortEvent(oPC); break;
|
||||
case 2: SpawnTributeEvent(oPC); break;
|
||||
case 3: SpawnAmbushEvent(oPC); break;
|
||||
case 4: SpawnAdventurerEvent(oPC); break;
|
||||
case 5: SpawnDemonEvent(oPC); break;
|
||||
case 6: SpawnBulliedEvent(oPC); break;
|
||||
case 7: SpawnMerchantEvent(oPC); break;
|
||||
case 8: SpawnBossEvent(oPC); break;
|
||||
case 9: SpawnFriendlyEvent(oPC); break;
|
||||
}
|
||||
}
|
||||
|
||||
//If it's a regular enemy encounter, spawn them
|
||||
SpawnRandomEnemies(oPC, sAreaString, nEncounterType);
|
||||
}
|
||||
Reference in New Issue
Block a user