Hour-based WayPoint Walker version 1.1
This is an upgrade to my previously posted Hour-based Waypoint Walker. This
update includes two enhancements:
1. The code no longer tries to find the nearest waypoint when deciding which
waypoint to start with. Instead, it keeps track of which waypoint the NPC is
going to, and if the NPC resumes walking waypoints after an interruption, he
will continue toward the waypoint he was walking toward before. If the NPC
has new waypoints to walk, then he will start at the first numerically.
2. The instructions now include setting up a userdefined event for running
HourWayPoints, and use SignalEvent(OBJECT_SELF, EventUserDefined(2000)) in
other scripts in place of HourWayPoints. This is so that NPCs that need to
call HourWayPoints with different parameters can do so by only having one
different script.
Instructions for setting it up are in the introductory comments. If you
already installed version 1.0, here are instructions for upgrading:
1. Completely replace the old rh_inc_hrwpoints with the new script below.
2. Replace the OnHeartbeat script with the new one below.
3. Save the OnUserDefined script below as nw_c2_defaultd to use it as the
default OnUserDefined script (different NPCs, of course, can and should have
their own modified versions with their events added in).
4. In MY_I0_GENERIC (or whatever you saved the modified NW_I0_GENERIC as),
where you replaced WalkWayPoints() with HourWayPoints(), now replace
HourWayPoints() with SignalEvent(OBJECT_SELF, EventUserDefined(2000)).
5. In your NPCs' OnSpawn script, also replace HourWayPoints() with
SignalEvent(OBJECT_SELF, EventUserDefined(2000)).
6. If you put HourWayPoints() in any other script (an End Conversation
script for your NPCs' conversations, perhaps), change it to
SignalEvent(OBJECT_SELF, EventUserDefined(2000)).
Here are the scripts, starting with rh_inc_hrwpoints:
NWScript:
void HourWayPoints(int nRun = FALSE, float fPause = 1.0, int nCircle = FALSE);
void HourRunCircuit(string sPrefix, int nWPStart = 1, int nReverse = FALSE, int nRun=FALSE, float fPause = 1.0, int nCircle = FALSE);
void HourGoToPost(object oPost, int nRun = FALSE);
int GetEventForWP(object oWP, int nNum);
string PosIntTo2DigitString(int nNum);
float GetFacingCorrectly(object oTarget);
void HourWayPoints(int nRun = FALSE, float fPause = 1.0, int nCircle = FALSE)
{
if (GetLocalInt(OBJECT_SELF, "nDontWalkWP"))
return;
string sWalker = GetTag(OBJECT_SELF);
string sWPPrefix;
string sPostPrefix;
int nWPStart = GetLocalInt(OBJECT_SELF, "nNextWP");
int nDay;
object oWP;
object oPost;
ClearAllActions();
sWPPrefix = "WP_00_";
sPostPrefix = "POST_00_";
oWP = GetObjectByTag(sWPPrefix + sWalker + "_01");
oPost = GetObjectByTag(sPostPrefix + sWalker);
if (GetIsObjectValid(oWP)) {
if (!nWPStart)
nWPStart = 1;
HourRunCircuit(sWPPrefix, nWPStart, FALSE, nRun, fPause, nCircle);
return;
}
if (GetIsObjectValid(oPost)) {
HourGoToPost(oPost, nRun);
return;
}
if (GetIsDay() || GetIsDawn()) {
sWPPrefix = "WP_DY_";
sPostPrefix = "POST_DY_";
nDay = 1;
} else {
sWPPrefix = "WP_NT_";
sPostPrefix = "POST_NT_";
nDay = 2;
}
oWP = GetObjectByTag(sWPPrefix + sWalker + "_01");
oPost = GetObjectByTag(sPostPrefix + sWalker);
if (GetIsObjectValid(oWP)) {
int nOldDay = GetLocalInt(OBJECT_SELF, "nDayPoints");
if (!(nWPStart && nOldDay && nOldDay == nDay)) {
SetLocalInt(OBJECT_SELF, "nDayPoints", nDay);
nWPStart = 1;
}
HourRunCircuit(sWPPrefix, nWPStart, FALSE, nRun, fPause, nCircle);
return;
}
if (GetIsObjectValid(oPost)) {
SetLocalInt(OBJECT_SELF, "nDayPoints", nDay);
HourGoToPost(oPost);
return;
}
int nHour = GetTimeHour();
sWPPrefix = "WP_" + PosIntTo2DigitString(nHour) + "_";
sPostPrefix = "POST_" + PosIntTo2DigitString(nHour) + "_";
oWP = GetObjectByTag(sWPPrefix + sWalker + "_01");
oPost = GetObjectByTag(sPostPrefix + sWalker);
if (!GetLocalInt(OBJECT_SELF, "nLastHourWalked"))
SetLocalInt(OBJECT_SELF, "nLastHourWalked", nHour + 1);
while (nHour != GetLocalInt(OBJECT_SELF, "nLastHourWalked")) {
if (GetIsObjectValid(oWP)) {
nWPStart = 1;
SetLocalInt(OBJECT_SELF, "nLastHourWalked", nHour);
SetLocalInt(OBJECT_SELF, "nLastHourChecked", GetTimeHour());
HourRunCircuit(sWPPrefix, nWPStart, FALSE, nRun, fPause, nCircle);
return;
} else if (GetIsObjectValid(oPost)) {
SetLocalInt(OBJECT_SELF, "nLastHourWalked", nHour);
SetLocalInt(OBJECT_SELF, "nLastHourChecked", GetTimeHour());
HourGoToPost(oPost, nRun);
return;
} else {
nHour--;
if (nHour == 0)
nHour = 24;
sWPPrefix = "WP_" + PosIntTo2DigitString(nHour) + "_";
sPostPrefix = "POST_" + PosIntTo2DigitString(nHour) + "_";
oWP = GetObjectByTag(sWPPrefix + sWalker + "_01");
oPost = GetObjectByTag(sPostPrefix + sWalker);
}
}
if (GetIsObjectValid(oWP)) {
SetLocalInt(OBJECT_SELF, "nLastHourWalked", nHour);
SetLocalInt(OBJECT_SELF, "nLastHourChecked", GetTimeHour());
HourRunCircuit(sWPPrefix, nWPStart, FALSE, nRun, fPause, nCircle);
return;
}
if (GetIsObjectValid(oPost)) {
SetLocalInt(OBJECT_SELF, "nLastHourWalked", nHour);
SetLocalInt(OBJECT_SELF, "nLastHourChecked", GetTimeHour());
HourGoToPost(oPost, nRun);
return;
}
}
void HourRunCircuit(string sPrefix, int nNext = 1, int nReverse=FALSE, int nRun=FALSE, float fPause = 1.0, int nCircle = FALSE)
{
string sWalker = GetTag(OBJECT_SELF);
object oWP = GetWaypointByTag(sPrefix + sWalker + "_" + PosIntTo2DigitString(nNext));
object oPost = GetWaypointByTag("POST_" + GetSubString(sPrefix, 3, 3) + sWalker);
if (GetIsObjectValid(oWP)) {
SetLocalInt(OBJECT_SELF, "nNextWP", nNext);
ActionMoveToObject(oWP, nRun);
SignalEvent(OBJECT_SELF, EventUserDefined(GetEventForWP(oWP, nNext)));
ActionWait(fPause);
if (!nReverse)
nNext++;
else
nNext--;
} else if (GetIsObjectValid(oPost)) {
ActionDoCommand(HourGoToPost(oPost, nRun));
return;
} else {
if (nCircle) {
nReverse = FALSE;
nNext = 1;
} else {
nReverse = !nReverse;
if (!nReverse)
nNext += 2;
else
nNext -= 2;
}
}
ActionDoCommand(HourRunCircuit(sPrefix, nNext, nReverse, nRun, fPause, nCircle));
}
void HourGoToPost(object oPost, int nRun = FALSE)
{
SetLocalInt(OBJECT_SELF, "nNextWP", 100);
ActionForceMoveToObject(oPost, nRun, 1.0, 60.0);
float fFacing = GetFacingCorrectly(oPost);
ActionDoCommand(SetFacing(fFacing));
SignalEvent(OBJECT_SELF, EventUserDefined(GetEventForWP(oPost, 0)));
}
string PosIntTo2DigitString(int nNum)
{
string sString;
if (nNum > 9)
return IntToString(nNum);
else if (nNum < 10 && nNum >= 0)
return ("0" + IntToString(nNum));
else
return "This function is not for negative numbers.";
}
float GetFacingCorrectly(object oTarget)
{
float fFacing;
fFacing = GetFacing(oTarget);
if (fFacing >= 360.0)
fFacing = 720.0 - fFacing;
return fFacing;
}
int GetEventForWP(object oWP, int nNum)
{
string sTime;
string sNum;
string sEventNum;
int nEventNum;
if (!nNum) {
sNum = "00";
sTime = GetSubString(GetTag(oWP), 5, 2);
}
else {
sNum = GetStringRight(GetTag(oWP), 2);
sTime = GetSubString(GetTag(oWP), 3, 2);
}
if (sTime == "DY")
sTime = "25";
else if (sTime == "NT")
sTime = "26";
sEventNum = "9" + sTime + sNum;
nEventNum = StringToInt(sEventNum);
return nEventNum;
}
And here is the OnHeartbeat script:
NWScript:
#include "MY_I0_GENERIC"
void main()
{
if(GetSpawnInCondition(NW_FLAG_FAST_BUFF_ENEMY))
{
if(TalentAdvancedBuff(40.0))
{
SetSpawnInCondition(NW_FLAG_FAST_BUFF_ENEMY, FALSE);
return;
}
}
if (GetLocalInt(OBJECT_SELF, "nDayPoints")) {
int nDay;
if (GetIsDay() || GetIsDawn())
nDay = 1;
else
nDay = 2;
if (GetLocalInt(OBJECT_SELF, "nDayPoints") != nDay)
SignalEvent(OBJECT_SELF, EventUserDefined(2000));
}
int nHour = GetTimeHour();
int nLastHourChecked = GetLocalInt(OBJECT_SELF, "nLastHourChecked");
if (nLastHourChecked && nHour != nLastHourChecked) {
string sWalker = GetTag(OBJECT_SELF);
object oNewWP;
object oNewPost;
while (nHour != nLastHourChecked) {
oNewWP = GetObjectByTag("WP_" + PosIntTo2DigitString(nHour) + "_" + sWalker + "_01");
oNewPost = GetObjectByTag("POST_" + PosIntTo2DigitString(nHour) + "_" + sWalker);
if (GetIsObjectValid(oNewWP) || GetIsObjectValid(oNewPost)) {
nHour = GetTimeHour();
nLastHourChecked = nHour;
}
else {
nHour--;
if (nHour == 0)
nHour = 24;
}
}
if (GetIsObjectValid(oNewWP) || GetIsObjectValid(oNewPost))
SignalEvent(OBJECT_SELF, EventUserDefined(2000));
else
SetLocalInt(OBJECT_SELF, "nLastHourChecked", GetTimeHour());
}
if(!GetHasEffect(EFFECT_TYPE_SLEEP))
{
if(!GetIsPostOrWalking())
{
if(!GetIsObjectValid(GetAttemptedAttackTarget()) && !GetIsObjectValid(GetAttemptedSpellTarget()))
{
if(!GetIsObjectValid(GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN)))
{
if(!GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL) && !IsInConversation(OBJECT_SELF))
{
if(GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS) || GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS_AVIAN))
{
PlayMobileAmbientAnimations();
}
else if(GetIsEncounterCreature() &&
!GetIsObjectValid(GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN)))
{
PlayMobileAmbientAnimations();
}
else if(GetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS) &&
!GetIsObjectValid(GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN)))
{
PlayImmobileAmbientAnimations();
}
}
else
{
DetermineSpecialBehavior();
}
}
else
{
}
}
}
}
else
{
if(GetSpawnInCondition(NW_FLAG_SLEEPING_AT_NIGHT))
{
effect eVis = EffectVisualEffect(VFX_IMP_SLEEP);
if(d10() > 6)
{
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, OBJECT_SELF);
}
}
}
if(GetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT))
{
SignalEvent(OBJECT_SELF, EventUserDefined(1001));
}
}
And here is the OnUserDefined script:
NWScript:
#include "MY_I0_GENERIC"
void main()
{
int nEvent = GetUserDefinedEventNumber();
switch(nEvent)
{
case 2000:
HourWayPoints(FALSE, 1.0, FALSE);
break;
}
}
Enjoy!
|