#include "dmfi_db_inc"
//This function calculates the resting duration based on PC Hit Dice
//Based off of restduration.2da
void FloatyText(string sText, object oPC, int iSettings)
{
if (!(iSettings & 0x40000000))
FloatingTextStringOnCreature(sText, oPC, FALSE);
}
float GetRestDuration(object oPC)
{
return 10.0f + 0.5f * IntToFloat(GetHitDice(oPC));
}
// This function is used as a wrapper for the Rest VFX Object
void DoRestVFX(object oPC, float fDuration, int nEffect) {
effect eEffect;
if (nEffect == -1) {
eEffect = EffectCutsceneImmobilize();
} else {
eEffect = EffectVisualEffect(nEffect);
}
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(eEffect), oPC, fDuration);
}
//This function adds the Blindness/Snore effects
//Also adds cutscene immobilize to prevent movement
//Snoring should only occur at start, then follows on the module's hb
void ApplyRestVFX(object oPC, int iSettings)
{
object oRestVFX = GetObjectByTag("dmfi_restvfxobject");
effect eSnore = EffectVisualEffect(VFX_IMP_SLEEP); //Sleepy "ZZZ"s
float fDuration = GetRestDuration(oPC);
float fSeconds = 6.0f;
if (!(iSettings & 0x80000000)) //Immobile Resting flag
{
// Pass a -1 for EffectCutsceneImmobilize.
// For a visual effect, simply pass the VFX constant.
AssignCommand(oRestVFX, DoRestVFX(oPC, fDuration, -1));
}
if (!(iSettings & 0x20000000)) //VFX flag
{
// AssignCommand(oRestVFX, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(eBlind), oPC, fDuration));
AssignCommand(oRestVFX, DoRestVFX(oPC, fDuration, VFX_DUR_BLACKOUT));
ApplyEffectToObject(DURATION_TYPE_INSTANT, eSnore, oPC);
}
}
// Removes blindness & immobilize -- Merle
void RemoveRestVFX(object oPC) {
object oRestVFX = GetObjectByTag("dmfi_restvfxobject");
effect eEffect = GetFirstEffect(oPC);
while (GetIsEffectValid(eEffect)) {
if (GetEffectCreator(eEffect) == oRestVFX) {
RemoveEffect(oPC, eEffect);
}
eEffect = GetNextEffect(oPC);
}
}
//This function gets the "Final HP" available to the PC after resting
int CalculateFinalHitPoints(object oPC, int iSettings)
{
int iHP = (iSettings & 0x0f000000);
switch(iHP)
{
case 0x01000000: return 0; break;
case 0x02000000: return GetHitDice(oPC); break;
case 0x03000000: return GetAbilityScore(oPC, ABILITY_CONSTITUTION); break;
case 0x04000000: return GetMaxHitPoints(oPC)/10; break;
case 0x05000000: return GetMaxHitPoints(oPC)/4; break;
case 0x06000000: return GetMaxHitPoints(oPC)/2; break;
case 0x07000000: return GetMaxHitPoints(oPC); break;
default: return GetMaxHitPoints(oPC); break;
}
return GetMaxHitPoints(oPC);
}
void RemoveMagicalEffects(object oPC)
{
effect eEffect = GetFirstEffect(oPC);
while (GetIsEffectValid(eEffect))
{
if (GetEffectSubType(eEffect) == SUBTYPE_MAGICAL)
RemoveEffect(oPC, eEffect);
eEffect = GetNextEffect(oPC);
}
}
//This function simulates a rest without restoring spells
void DoPseudoRest(object oPC, int iSettings, int iSpells = FALSE)
{
effect eSnore = EffectVisualEffect(VFX_IMP_SLEEP);
effect eBlind = EffectVisualEffect(VFX_DUR_BLACKOUT);
effect eStop = EffectCutsceneImmobilize();
float fDuration = GetRestDuration(oPC);
float fSeconds = 6.0f;
int iAnimation = GetLocalInt(oPC, "dmfi_r_alternate");
if (!iAnimation)
iAnimation = ANIMATION_LOOPING_SIT_CROSS;
AssignCommand(oPC, PlayAnimation(iAnimation, 1.0f, fDuration));
DelayCommand(0.1, SetCommandable(FALSE, oPC));
DelayCommand(fDuration, SetCommandable(TRUE, oPC));
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(eStop), oPC, fDuration);
if (!(iSettings & 0x20000000) && iAnimation != ANIMATION_LOOPING_MEDITATE && iAnimation != ANIMATION_LOOPING_WORSHIP) //If the No VFX flag is not set, do VFX
{
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(eBlind), oPC, fDuration);
ApplyEffectToObject(DURATION_TYPE_INSTANT, eSnore, oPC);
while (fSeconds < fDuration)
{
DelayCommand(fSeconds, ApplyEffectToObject(DURATION_TYPE_INSTANT, eSnore, oPC));
fSeconds += 6.0f;
}
}
if (!iSpells)
{
effect eHeal = EffectHeal(CalculateFinalHitPoints(oPC, iSettings)); //Heal the PC
DelayCommand(fDuration + 0.1f, ApplyEffectToObject(DURATION_TYPE_INSTANT, eHeal, oPC));
DelayCommand(fDuration + 0.1f, RemoveMagicalEffects(oPC)); //Remove all magical effects from PC
}
else
{
DelayCommand(fDuration + 0.1f, ForceRest(oPC));
}
DeleteLocalInt(oPC, "dmfi_r_alternate");
}
//This function determines if the PC is wearing heavy armor
int GetIsWearingHeavyArmor(object oPC, int iSettings)
{
int iArmor = (iSettings & 0x00f00000);
object oArmor = GetItemInSlot(INVENTORY_SLOT_CHEST, oPC);
int iWeight = GetWeight(oArmor);
switch(iArmor)
{
default:
case 0x00100000: if (iWeight > 20) return TRUE; break;
case 0x00200000: if (iWeight > 60) return TRUE; break;
case 0x00300000: if (iWeight > 110) return TRUE; break;
case 0x00400000: if (iWeight > 160) return TRUE; break;
case 0x00500000: if (iWeight > 310) return TRUE; break;
case 0x00600000: if (iWeight > 410) return TRUE; break;
case 0x00700000: if (iWeight > 460) return TRUE; break;
}
return FALSE;
}
//This function determines if the PC is near a resting placeable
int GetIsNearRestingObject(object oPC, int iSettings)
{
if (iSettings & 0x00020000) //Ignore Druid
{
if (GetLevelByClass(CLASS_TYPE_DRUID, oPC))
return TRUE;
}
if (iSettings & 0x00040000) //Ignore Ranger
{
if (GetLevelByClass(CLASS_TYPE_RANGER, oPC))
return TRUE;
}
if (iSettings & 0x00080000) //Ignore Barb
{
if (GetLevelByClass(CLASS_TYPE_BARBARIAN, oPC))
return TRUE;
}
object oPlaceable = GetFirstObjectInShape(SHAPE_SPHERE, 6.0f, GetLocation(oPC), TRUE, OBJECT_TYPE_PLACEABLE);
while (GetIsObjectValid(oPlaceable))
{
if (!(iSettings & 0x00001000) && GetTag(oPlaceable) == "dmfi_rest") //DMFI Placeables: by default, ON
return TRUE;
if ((iSettings & 0x00002000) && GetStringLowerCase(GetName(oPlaceable)) == "campfire") //Campfires
return TRUE;
if ((iSettings & 0x00004000) && (GetStringLowerCase(GetName(oPlaceable)) == "bed roll" || GetStringLowerCase(GetName(oPlaceable)) == "bedroll")) //Bed rolls
return TRUE;
if ((iSettings & 0x00008000) && GetStringLowerCase(GetName(oPlaceable)) == "bed") //beds
return TRUE;
if ((iSettings & 0x00010000) && GetStringLowerCase(GetName(oPlaceable)) == "tent") //tents
return TRUE;
oPlaceable = GetNextObjectInShape(SHAPE_SPHERE, 6.0f, GetLocation(oPC), TRUE, OBJECT_TYPE_PLACEABLE);
}
return FALSE;
}
// Updated to allow 6 hour breaks and to pass in a percentage if rest is interrupted
void SetNextRestTime(object oPC, int iSettings, float fPercentage = 1.0)
{
if (fPercentage > 1.0 || fPercentage <= 0.0) {
fPercentage = 1.0;
}
int iHours = (iSettings & 0x00000f00);
int iTime = GetTimeHour() + GetCalendarDay() * 24 + GetCalendarMonth() * 24 * 28 + GetCalendarYear() * 24 * 28 * 12;
switch(iHours)
{
default:
case 0x00000100: SetLocalInt(oPC, "dmfi_r_nextrest", iTime + FloatToInt(IntToFloat(1) * fPercentage)); break;
case 0x00000200: SetLocalInt(oPC, "dmfi_r_nextrest", iTime + FloatToInt(IntToFloat(2) * fPercentage)); break;
case 0x00000300: SetLocalInt(oPC, "dmfi_r_nextrest", iTime + FloatToInt(IntToFloat(4) * fPercentage)); break;
case 0x00000400: SetLocalInt(oPC, "dmfi_r_nextrest", iTime + FloatToInt(IntToFloat(6) * fPercentage)); break;
case 0x00000500: SetLocalInt(oPC, "dmfi_r_nextrest", iTime + FloatToInt(IntToFloat(
* fPercentage)); break;
case 0x00000600: SetLocalInt(oPC, "dmfi_r_nextrest", iTime + FloatToInt(IntToFloat(12) * fPercentage)); break;
case 0x00000700: SetLocalInt(oPC, "dmfi_r_nextrest", iTime + FloatToInt(IntToFloat(24) * fPercentage)); break;
}
}
//This function determines whether or not you can rest.
int DMFI_CanIRest(object oPC, int iSettings)
{
if (GetIsDM(oPC)) return TRUE;
if (iSettings & 0x00000002) //No Rest Override
{
if (iSettings & 0x00000080)
FloatyText("This is a No Rest area", oPC, iSettings);
return FALSE;
}
if (!(iSettings & 0x00000001)) //Unlimited Rest Override
{
if (iSettings & 0x00000080)
FloatyText("This is an Unlimited Rest area", oPC, iSettings);
return TRUE;
}
if ((iSettings & 0x00000004) && (iSettings & 0x00000001)) //Time restriction
{
int iTime = GetTimeHour() + GetCalendarDay() * 24 + GetCalendarMonth() * 24 * 28 + GetCalendarYear() * 24 * 28 * 12;
if (iTime < GetLocalInt(oPC, "dmfi_r_nextrest"))
{
FloatyText("You cannot rest at this time. You may rest again in " + IntToString(GetLocalInt(oPC, "dmfi_r_nextrest") - iTime) + " hours.", oPC, iSettings);
return FALSE;
}
}
if ((iSettings & 0x00000008) && (iSettings & 0x00000001)) //Placeable restriction
{
if (!GetIsNearRestingObject(oPC, iSettings))
{
FloatyText("You are not near a rest placeable", oPC, iSettings);
return FALSE;
}
}
if ((iSettings & 0x00000010) && (iSettings & 0x00000001)) //Armor restriction
{
if (GetIsWearingHeavyArmor(oPC, iSettings))
{
FloatyText("Your current armor is too heavy to rest", oPC, iSettings);
return FALSE;
}
}
return TRUE;
}
void main()
{
object oPC = GetLastPCRested();
object oArea = GetArea(oPC);
int iSettings;
int iModSettings = GetDMFIPersistentInt("dmfi", "dmfi_r_");
int iAreaSettings = GetDMFIPersistentInt("dmfi", "dmfi_r_" + GetTag(oArea));
if (iAreaSettings & 0x00000080)
{
iSettings = iAreaSettings;
}
else
{
iSettings = iModSettings;
}
SetLocalInt(oPC, "dmfi_r_settings", iSettings);
if (GetLastRestEventType()==REST_EVENTTYPE_REST_STARTED)
{
SetLocalInt(oPC, "dmfi_norest", !(DMFI_CanIRest(oPC, iSettings)));
SetLocalInt(oPC, "dmfi_r_hitpoints", GetCurrentHitPoints(oPC));
if (GetIsDM(oPC) || (!(iSettings & 0x10000000) && !GetLocalInt(oPC, "dmfi_r_bypass")))
{ //If the Rest Conversation variable is set, then activate the rest conversation here.
AssignCommand(oPC, ClearAllActions());
SetLocalString(oPC, "dmfi_univ_conv", "rest");
AssignCommand(oPC, ActionStartConversation(oPC, "dmfi_universal", TRUE));
return;
}
if (GetLocalInt(oPC, "dmfi_norest")) //PC cannot rest
{
AssignCommand(oPC, ClearAllActions());
DeleteLocalInt(oPC, "dmfi_r_bypass");
return;
}
if ((iSettings & 0x00000004) && (iSettings & 0x00000001)) //Time restriction
SetNextRestTime(oPC, iSettings);
if (GetLocalInt(oPC, "dmfi_r_alternate") || ((iSettings & 0x00000040) && (iSettings & 0x00000001)))
{
AssignCommand(oPC, ClearAllActions());
if ((iSettings & 0x00000040) && (iSettings & 0x00000001))
FloatyText("You cannot regain your spells in this area",oPC, iSettings);
DoPseudoRest(oPC, iSettings, ((iSettings & 0x00000040) && (iSettings & 0x00000001)));
DeleteLocalInt(oPC, "dmfi_r_bypass");
return;
}
else if (!(iSettings & 0x20000000))
{ //Rest VFX
ApplyRestVFX(oPC, iSettings);
}
if ((iSettings & 0x00000020) && (iSettings & 0x00000001))
{ //Auto Party Drop
FloatyText("You have been removed from the party to prevent rest canceling",oPC, iSettings);
RemoveFromParty(oPC);
}
}
else if (GetLastRestEventType()==REST_EVENTTYPE_REST_CANCELLED)
{
// Make sure that resting has been initialized and the start time has been set. Otherwise, the Cancelled Rest Event was fired by
// the Resting conversation.
if (GetLocalInt(oPC, "dmfi_r_init"))
{
int iTime = GetTimeSecond() + GetTimeMinute() * 60 + GetTimeHour() * 3600 + GetCalendarDay() * 24 * 3600 + GetCalendarMonth() *3600 * 24 * 28 + GetCalendarYear() * 24 * 28 * 12 * 3600;
int nTimeRested = iTime - GetLocalInt(oPC, "dmfi_r_startseconds");
int nFullTime = FloatToInt(GetRestDuration(oPC));
float fPercentage = IntToFloat(nTimeRested) / IntToFloat(nFullTime);
SetNextRestTime(oPC, iSettings, fPercentage);
// SendMessageToPC(oPC, "Rest interrupted; resting for " + IntToString(nTimeRested) + " out of " + IntToString(nFullTime) + " seconds (" + FloatToString(fPercentage) + "%).");
SetLocalInt(oPC, "dmfi_r_init", FALSE);
if ((iSettings & 0x00000020) && GetCurrentHitPoints(oPC) > GetLocalInt(oPC, "dmfi_r_hitpoints") && iSettings & 0x00000001) //HP restriction
{
effect eDam = EffectDamage(GetMaxHitPoints(oPC) - GetLocalInt(oPC, "dmfi_r_hitpoints"));
FloatyText("Your hitpoints have been reset",oPC, iSettings);
AssignCommand(oPC, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oPC));
}
}
RemoveRestVFX(oPC);
}
else if (GetLastRestEventType()==REST_EVENTTYPE_REST_FINISHED)
{
if ((iSettings & 0x00000020) && (iSettings & 0x00000001)) //HP restriction
{
int iDam = GetMaxHitPoints(oPC) - GetLocalInt(oPC, "dmfi_r_hitpoints") - CalculateFinalHitPoints(oPC, iSettings);
if (iDam > 0)
{
effect eDam = EffectDamage(iDam);
FloatyText("You gain back limited HP from this rest",oPC, iSettings);
AssignCommand(oPC, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oPC));
}
}
}
DeleteLocalInt(oPC, "dmfi_r_bypass");
}
Well the below script is basically setting up a timer for how long a player has to wait till he can rest again but ONLY if the player is in the posession of a campfire (placeable spawner) or a bedroll (which is an item the player will need to have in his posession)
So seeing that I seem to "screw" this merging up the entire time I was hoping someone could help me with this.
additional newbie request(?): would it also be possible to add like a percentage roll for being ambushed while you are resting in hostile area's?