So what we are looking for is a script that can so a lot of different things so that you don't need to keep rewriting similar scripts to clog up a module. The example I will be using is an area damage script that is versatile enough to handle any type of extreme or mildly painful environmental condition a builder can think of. It should also be able to handle different amounts of damage during different time periods and different types of damage. It goes something like this as an example:
lets say that a group of people want to explore Antarctica and reach the south pole. As they start the journey and go through areas its going to get colder. So perhaps you want to have a check for cold damage and make your cold damage checks closer together at greater saves for more points as they journey area to area. Now lets say they find an active volcano with lots of caves to explore. Some are so hot they need to check for fire damage. Some have acid all over and they have to check with acid damage. We are going to handle all of this with one script.
The first thing we need to do is to create a function to define what ambient damage is and another to handle and do the damage to pcs entering the area.
* a few notes first I'm doing this a little backwards so its easier to understand normally you would write the script and plug the variables in but here its easier to explain all this in a backward sort of way.*
*Also the script was created by Mermut for harvest moon it is a marvel of elegance in scripting.*
Ok back to our regularly featured program. Here is your function include:
Code: Select all
// Ambient Area Damage Function
// Roll iCount of iDie to determine damage of iDamageType to oPC while
// they are in oArea if they fail a fort save of iFortDC. The Fort
// Save/damage runs every fHB_Time seconds.
// The values for everything except oPC and oArea are pulled from variables
// set on the area.
void AmbientDamage(object oPC, object oArea);
void DoDamage(object oPC, object oArea, int iDie, int iCount, int iType, int iFortDC, float fDelay)
{
// check again for PC in the area in case the PC has left
// during the delay
if (GetArea(oPC) != oArea)
return;
// Determine the amount of damage by converting iDie into the
// appropriate d#() function
int iDamage;
if (iDie <= 2)
iDamage = d2(iCount);
else if (iDie == 3)
iDamage = d3(iCount);
else if (iDie < 6)
iDamage = d4(iCount);
else if (iDie < 8)
iDamage = d6(iCount);
else if (iDie < 10)
iDamage = d8(iCount);
else if (iDie < 12)
iDamage = d10(iCount);
else if (iDie < 20)
iDamage = d12(iCount);
else if (iDie < 100)
iDamage = d20(iCount);
else // if iDie >= 100
iDamage = d100(iCount);
// run the fort save, if they fail, do damage
if (!FortitudeSave(oPC, iFortDC, SAVING_THROW_TYPE_NONE, oPC))
{
effect eDamage = EffectDamage(iDamage, iType);
ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage,oPC);
}
DelayCommand(fDelay, DoDamage(oPC, oArea, iDie, iCount, iType, iFortDC, fDelay));
}
void AmbientDamage(object oPC, object oArea)
{
// only do damage to creatures in the area, exclude DM avatars
if (GetArea(oPC) != oArea || GetIsDM(oPC))
return;
int iDie = GetLocalInt(oArea, "iDie");
int iCount = GetLocalInt(oArea, "iCount");
int iType = GetLocalInt(oArea, "iDamageType");
int iFortDC = GetLocalInt(oArea, "iFortDC");
float fDelay = GetLocalFloat(oArea, "fHB_Time");
// if no damage type or amount is set, exit
if (iDie == 0 || iType == 0)
return;
// set default values for iCount, iFortDC and iHB_Time if they are unset
if (iCount <= 0)
iCount = 1;
if (iFortDC <= 0)
iFortDC = 10;
if (fDelay <= 0.5)
fDelay = 10.0;
DoDamage(oPC, oArea, iDie, iCount, iType, iFortDC, fDelay);
}
Code: Select all
#include "24areaevents"
#include "mer_amb_damage"
void main()
{
object oPC = GetEnteringObject();
object oArea = GetArea(oPC);
int iTimeStopCastings = GetLocalInt(oArea, "TIME_STOP_ACTIVE");
// Set it so monsters use spellhooks too
SetLocalInt(oArea, "X2_L_WILD_MAGIC", TRUE);
DelayCommand(0.4, AmbientDamage(oPC, oArea));
if (iTimeStopCastings > 0)
{
int iTimeStopCastTime = GetLocalInt(oArea, "TIME_STOP_CAST");
float iTimeStopDuration = IntToFloat((GetTimeHour()*60 +
GetTimeMinute())*60 + GetTimeSecond() - iTimeStopCastTime) + 9.75;
effect eTime = EffectCutsceneParalyze();
DelayCommand(0.75, ApplyEffectToObject(DURATION_TYPE_TEMPORARY,
eTime, oPC, iTimeStopDuration));
}
if (GetIsPC(oPC) && !GetIsDM(oPC) && !GetIsDMPossessed(oPC))
{
SetLocalObject(oPC, "CURRENTAREA", oArea);
SetLocalInt(oArea, "PCINAREA", GetLocalInt(oArea, "PCINAREA") + 1);
DelayCommand(0.5,ExecuteScript("24subraceenter", oPC));
}
// Send area description, if one exists
if (GetIsPC(oPC))
{
string sDescription = GetLocalString(oArea, "sDescription");
if (sDescription != "")
{
string sTag = GetTag(oArea) + "_d";
// only send PC description once per server restart
// so they don't get too annoyed
if (!GetLocalInt(oPC, sTag))
{
DelayCommand(5.0, FloatingTextStringOnCreature(sDescription, oPC, FALSE));
SetLocalInt(oPC, sTag, TRUE);
}
}
}
// if the area is set to make snow drifts, so do
if (GetLocalInt(oArea, "MakeSnow"))
ExecuteScript("mer_makesnow", oArea);
SetAreaEventType(EVENT_AREA_ONENTER);
DelayCommand(0.1, ExecuteScript(GetTag(oArea), oArea));
int count;
int iNumExecuteScripts = GetLocalInt(oArea, "ONENTER_EXECUTE");
for (count = 1; count <= iNumExecuteScripts; count++)
{
ExecuteScript(GetLocalString(oArea,
"ONENTER_EXECUTE_" + IntToString(count)), oArea);
}
}
And on the 13th line of the script you see the function in use: DelayCommand(0.4, AmbientDamage(oPC, oArea));
We still have the question where are you getting the variables. Well the script extracts the variables from the areas themselves.
Now open up your area properties box. Once you get your area properties box go to the advanced tab. From there at the bottom of the list is the word variables with a button beside it. If you hit that button you a box will appear with two separation lines. it will have NAME in the first section-- TYPE in the second-- VALUE in the third. This is where you plug in the variables for the script to work. I'm using the variables from an area in Harvest Moon:
fHB_Time -----------------Float ------------ 20
iCount -------------------- Int----------------- 2
iDamageType ------------ Int----------------32 (Cold damage taken from 2da format)
iDie ----------------------- Int------------------6
iFortDC ------------------ Int------------------25
NoRest ------------------- Int--------------------1
NoRestMessage---------- String-------------- It is to cold to rest you need to find Shelter
So if you plug in all these variables - the NoRest and NoRestMessage being optional and some others you have a functioning script that can do any iDamageType by 2da reference in the amount of dice that you want on any area and can change it up by putting different integers on different areas. One script thats all you need when you use the variable boxes on areas. You can also make scripts for peaceables to do multiple tasks using this basic layout.