Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - Cruzel

#1
General Discussion / Re: Positive Vibes Corner
February 15, 2021, 06:48:23 PM
My favorite thing about EFU is that it's a server where everyone can shine, even the hilariously incompetent. Failure can  often lead to wonderful and meaningful interactions, with consequence and memorable events for all involved, far more so than success could have.

Be it being fed to a giant beholder to enhance someone else's story, or climbing into that beholder's mouth yourself just to say "hello"...

In this community, even the worst of us can make magic happen.
#2
The pillar breaks invis presumably bc the King/DMs wants sporting challenge and whatnot?

Make it so the random potion and item drops during dispensaries will reveal the player picking them up. The last few dispensaries I've seen, there have been PCs ninja-grabbing runes and prestigious goods.

I get that there are sparks and etc. in the meantime, but ninja-looting is boring and unfun gameplay. Impose a risk on opportunism so the ballsy people can be ballsy and steal stuff/get called on it ICly
#3
Rowan's store now seems to accept things for sale, that given the nature of his store seems unintentional.

Various things that are generally sellable only to toyfolly or the late jebedezra jeckyls can be sold to Rowan for the prices offered by the latter.  PM me for details.
#4
Screen Shots & Obituaries / Re: Rithwarian Luelana
January 11, 2020, 08:28:33 AM
After your PC before her was Marco's greatest frenemy, I'm glad I recruited you with marco into the guild, because you took it and ran with it in a way I never had the energy to. You did a fantastic job as a herald of woe.  Good shit friendo
#5
I think the point of the expense is a cultural one that has existed in all chapters of EFU:

If you want to LOOK GOOD It's going to cost you.

Yes, you can loot some pretty good armor. But most of it comes with drawbacks, or just looks plain awful.  Looking good and getting save/skill bonuses without drawbacks is a pretty huge deal on EFU.  These denote PCs who are wealthy, or at least capable enough to generate the GP to be a valuable asset to another player pushing plots and whatnot.

It's also a huge discrepancy to encourage people from playing generic 12 dex fullplate fighters for max AC. Other other types have more flavor, so they're cheaper, and more viable to craft and find loot for as a rule.

I could get behind being able to change the bonuses without having to craft an entirely new armor, but the prices are mostly fair if you consider the reasoning and behind them.
#6
I may or may not be leaving, or having much/any time to play.  Shit just hit the fan IRL and chances are I'll be moving and getting several new jobs to make sure my kid's ok.

Sorry nerds but EFU just can't be a priority while I sort some shit out!
#7
Suggestions / Re: Paladin Alignment Restrictions
November 04, 2019, 10:15:49 PM
Non-good oaths should require an app, since most people fumble with LG and oath-based PCs anyways.
#8
Suggestions / Re: Necromancy- De-Animating Corpses
November 02, 2019, 01:07:08 AM
This should be possible and fairly easy to do, if the DMs desire it.
#9
Bug Reports / Re: Bundle of blur removes potions
October 30, 2019, 12:18:23 AM
This happens as a result of the bundles that create stackable items, if you already have a stack of those items. It will get eaten, and you're left only with whatever the  bundle gave you.

In the meantime if you open bundles like this, put the existing potions in a bag or on the ground and they will not be destroyed by the script mistakenly
#10
Player Workshop / Undead 2.0
October 16, 2019, 08:06:22 PM
Ok.  These are scripts that work 100% as-is, but will need some tweaks to work properly with EFU systems. I left in the placeholders and debugs so other workshop friends can fiddle :)

This requires a lot of little tweaks to a lot of scripts, so here's the breakdown:

What this all does:

Creates an object rather than a summon effect. This means the zombo will remain after logout, fully buffed, enchanced and whatnot. It can be freely released and reclaimed, allowing necromancers to "Store" their undead friends in a secluded place while they visit hubs and such, and reclaim them later. They are flagged appropriately so that dismissal/banishment can still affect them, despite not being summons.

ANIMATE DEAD SPELLSCRIPT
[hide]  Not much of this is needed.  Delete the EffectSummonCreatre() and replace it with  all code between "KEEP BELOW" and "KEEP ABOVE" Swap out the variable names for what is used for EFU summoning points.  (Possibly necessary:  Add function from a later snippet to manually unsummon mirror images/other summons, but ONLY IF efu's spellhook does not handle this already)
Quote#include "x2_inc_spellhook"

void main()
{

/*
  Spellcast Hook Code
  Added 2003-06-23 by GeorgZ
  If you want to make changes to all spells,
  check x2_inc_spellhook.nss to find out more

*/

    if (!X2PreSpellCastCode())
    {
    // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell
        return;
    }

// End of Spell Cast Hook


    //Declare major variables
    int nMetaMagic = GetMetaMagicFeat();
    object oPC = OBJECT_SELF;
    int nCasterLevel = GetCasterLevel(OBJECT_SELF);
    int nDuration = GetCasterLevel(OBJECT_SELF);
    nDuration = 24;
    //effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD);
    effect eSummon;
    //Metamagic extension if needed
    int nSummoningPoints = GetLocalInt(oPC, "nSummonPool");   // REPLACE WITH EFU VARIABLES
    int nSummonMax       = GetLocalInt(oPC, "nSumMax");       // Replace with EFU VARIABLES

// Placeholder mostly. The ONLY line that matters here for efu is between the next comments

    if (nSummoningPoints <= nSummonMax)  // Check for room in summoning pool. Existing EFU  Function, insert below code into that function
      {
      // KEEP BELOW
       string sTag = "NW_S_ZOMBTYRANT";  // Replace this placeholder with whatever you use to determine what strref animate dead summons.
       object oZombo = CreateObject(OBJECT_TYPE_CREATURE, sTag, GetSpellTargetLocation(), FALSE, "zombo_"+GetPCPublicCDKey(oPC));
        ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD), GetSpellTargetLocation());
        SetLocalInt(oZombo, "nDismissable", 1); // Add variable for dismissal and banishment to see it as a target
        AddHenchman(oPC, oZombo);


        SetLocalInt(oZombo, "nSummonCost", 10);    // placeholder for debug so I wouldn't have to make a creature template w/ variables. Delete this.
        SetLocalInt(oPC, "nSummonPool", nSummoningPoints + GetLocalInt(oZombo, "nSummonCost")); // REPLACE WITH EFU VARIABLES FOR CURRENT POOL AND THE SUMMON'S COST

      // KEEP ABOVE

// INSERT OPTIONAL SUMMON/MIRROR HANDLES HERE IF NEEDED.





      }
}

[/hide]

Update to RELEASE UNDEAD player tool:   (Rename it to Release/Reclaim Undead)
[hide]

Very straightforward. If undead is clicked while owned, it releases.   If  undead is clicked by a PC who didn't make it, or a PC who is at/over their summoning pool limit, nothing happens.  Otherwise if clicking their own zombies while released (or after logout) the zombie is reclaimed.  Clicking on self will recalculate the summoning pool for the PC and fix any errors.

Quote
void main()
{
object oPC = OBJECT_SELF;
object oTarget = GetSpellTargetObject();
location lTarget = GetSpellTargetLocation();
string sTag = GetTag(oTarget);
int nMax = GetLocalInt(oPC, "nSumMax");               // Replace with EFU variables for summoning pool CAP
int nCost = GetLocalInt(oTarget, "nSummonCost");      // Replace with EFU variables for how much the minion costs
int nPool = GetLocalInt(oPC, "nSummonPool");          // Replace with EFU variables for how many points PC is currently using from pool.

//Manually recalculate summoning pool if self is targeted. This closes off errors caused by edge cases

if (oTarget == oPC)
{
int i =1;
SetLocalInt(oPC, "nSummonPool", 0);
object oHench = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, i);
object oSummon = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, i);
// REPLACE WITH EFU VARIABLES. Loops through each hench, grabbing their variables, then each minion
while (GetIsObjectValid(oHench) != FALSE)
   {
    nPool = GetLocalInt(oPC, "nSummonPool");
    nCost = GetLocalInt(oHench, "nSummonCost");
    SetLocalInt(oPC, "nSummonPool", nPool + nCost);
    oHench = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, i++);
   }
// Remove below, if summons + undead at same time undesired.
i = 1;

    while (GetIsObjectValid(oSummon) != FALSE)
     {
        nPool = GetLocalInt(oPC, "nSummonPool");
        nCost = GetLocalInt(oSummon, "nSummonCost");
        SetLocalInt(oPC, "nSummonPool", nPool + nCost);
         oSummon = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, i++);
     }
// Remove above if summons + undead undesired

//Feedback Message.
  SendMessageToPC(oPC, "Summoning Pool Recalculated: You now have " + IntToString(GetLocalInt(oPC, "nSummonPool")) + " out of " + IntToString(GetLocalInt(oPC, "nSumMax")) + " points available ");
  return;
}


// Auth Check to See if the PC created this zombo; Play message and abort if not the creator
if (sTag != "zombo_"+GetPCPublicCDKey(oPC)) { SendMessageToPC(oPC, "This creature was not animated by you, or is not undead. It will not follow your commands."); return; }



// Auth Check to verify summoning pool cap. Placeholder function, as this can be copy/pasted from summon scripts.
if ((nPool + nCost) >= nMax )
{ SendMessageToPC(oPC, "This creature is too powerful to control in addition to those you have already summoned"); return; }


// Remove the Henchman if already controlled. Modify summoning pool accordingly.

if (GetMaster(oTarget) == oPC)

  {
   RemoveHenchman(oPC, oTarget);
   SetLocalInt(oPC, "nSummonPool", nPool - nCost);  // Lower pool cost. Replace variables with EFU ones
   SendMessageToPC(oPC, "This minion has been released from your control and will act of its own accord"); //Debug, remove if desired.
   // add VFX if desired.
  }


// Otherwise, we take control and modify the pool;
else
{
   AddHenchman(oPC, oTarget);
   ClearPersonalReputation(oTarget, oPC); // Edge Case handle: if the PC had hit them with an AOE or something while released. Stop your own zombos from killing you while blue.
   SetLocalInt(oPC, "nSummonPool", nPool + nCost);  // Lower pool cost. Replace variables with EFU ones
   SendMessageToPC(oPC, "This undead creature bends once more to your will as your magics influence it."); //Debug, remove if desired.
  // add VFX if desired.


  // BELOW TWO FUNCTIONS PERFORM SAME PURPOSE. CHOOSE WHICH IS IDEAL

                                   // OPTION ONE:

   //  INSERT "Fake" SUMMON EVENT HERE TO UNSUMMON MIRROR IMAGES (AND OTHER SUMMONS IF DESIRED) Ugly, but cleanest and cheapest for CPU. Debug mostly.
   // Recommended not to use this unless necessary.
   ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, EffectSummonCreature(""),lTarget, 0.01);


                              // OPTION TWO

     //  This lets you keep summons out but will destroy mirror images. "nMirror" must be swapped to whatever identifier you have on mirror clones.
   //  Or manually loop associates and poof the images. Less ideal, more GPU cost.
   int i =1;
   object oMirror = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, i);

   while (GetIsObjectValid(oMirror) != FALSE)
   {
     if (GetLocalInt(oMirror, "nMirror") == 1)    // make sure they're flagged as a mirror image, prevents shenanigans with things the PC didn't create
      {
       DestroyObject(oMirror);
      }
    oMirror = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC, i++);
   }

}


}
[/hide]

OnModuleLoad()
[hide]
Here, all we need is one line.
Quote

SetMaxHenchmen(X);

Replace X with something reasonable (20-25?).  This variable controls the maximum amount of "henchmen" type minions a PC can have. Set it too low, and a player might hit the cap despite having more room in their pool. 

[/hide]

Zombie OnDeath() Event:
[hide]
Very Simple  addition;  Allow us to  make sure summon pool updates properly as zombos die.
Quote
object oMaster = GetMaster(OBJECT_SELF);
SetLocalInt(oMaster, "nSummonPool",GetLocalInt(oMaster, "nSummonPool" ) -  GetLocalInt(OBJECT_SELF, "nSummonCost"));
[/hide]

On client enter
[hide]
This is probably already a thing. Clear the summoning pool variable, since the PC won't be controlling anything when they login.  if this isn't there, use appropriate summoning pool variable
Quote
SetLocalInt(oPC, "nSummonPool", 0);
/quote]
[/hide]
DISMISSAL/BANISHMENT CHANGES

[hide]

There's probably already another function added to these to handle mirror images. You can pretty much copy/paste those.  and all you need to add is the following, to your conditional statement.

Quote
|| GetLocalInt(oTarget, "nDismissable") == 1

The code in practice, for the workship fiddlers;

Quote
#include "X0_I0_SPELLS"
#include "x2_inc_spellhook"

void main()
{

/*
  Spellcast Hook Code
  Added 2003-06-20 by Georg
  If you want to make changes to all spells,
  check x2_inc_spellhook.nss to find out more

*/

    if (!X2PreSpellCastCode())
    {
    // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell
        return;
    }

// End of Spell Cast Hook


    //Declare major variables
    object oMaster;
    effect eVis = EffectVisualEffect(VFX_IMP_UNSUMMON);
    effect eImpact = EffectVisualEffect(VFX_FNF_LOS_EVIL_30);
    ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpact, GetSpellTargetLocation());
    int nSpellDC;
    //Get the first object in the are of effect
    object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(OBJECT_SELF));
    while(GetIsObjectValid(oTarget))
    {
        //does the creature have a master.
        oMaster = GetMaster(oTarget);
        //Is that master valid and is he an enemy
        if((GetIsObjectValid(oMaster) && spellsIsTarget(oMaster,SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF )) || GetLocalInt(oTarget, "nDismissable") == 1 )
        //added zombo condition to above
        {
            //Is the creature a summoned associate
            if(GetAssociate(ASSOCIATE_TYPE_SUMMONED, oMaster) == oTarget ||
               GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oMaster) == oTarget ||
               GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oMaster) == oTarget
               || GetLocalInt(oTarget, "nDismissable") == 1 )     // Zombo dismissing addition
            {
                SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_DISMISSAL));
                //Determine correct save
                nSpellDC = GetSpellSaveDC() + 6;
                //Make SR and will save checks
                if (!MyResistSpell(OBJECT_SELF, oTarget) && !MySavingThrow(SAVING_THROW_WILL, oTarget, nSpellDC))
                {
                     //Apply the VFX and delay the destruction of the summoned monster so
                     //that the script and VFX can play.
                     ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget);
                     DestroyObject(oTarget, 0.5);
                }
            }
        }
        //Get next creature in the shape.
        oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(OBJECT_SELF));
    }
}
[/hide]

KNOWN ISSUES:

Really the only big ones are:
- if the PC clicks "remove from party" from the radial, instead of using the release tool, the summoning pool will not change to reflect this.  A NWNX hook probably exists that can fix this. Clicking the player tool on self fixes this.
-Players cannot unsummon from radial anymore.   A player tool or /c command would be needed to destroy them manually. (Personally,  I like the idea of having undead linger unless physically destroyed)
#11
Bug Reports / Combat Dummies
October 12, 2019, 02:13:37 PM
The XP tick seems pretty hit and miss.  I've been wailing on one for close to 12 minutes w/ 2 apr and  gotten about 30 XP at level 5

Sometimes the ticks roll in from consecutive hits, others I'll go quite a few rounds without seeing xp at all.  I've messed around w/ trying to alternate dummies, dualwielding vs 1h, but it seems mostly random/irregular?

More of a suggestion, but They've also apparently got a TON of hp. I've easily done somewhere between 300-500 damage without destroying it in this time.  If this is meant to be a safer / less supply rewarding means for lowbies to level or recover levels..  It seems very unworth the time atm.
#12
Suggestions / Remove/Tweak Disarm from NPCS
October 11, 2019, 03:34:15 AM
Not the first time it's come up, but man. This is beyond frustrating when it happens. We seem to be getting more and more NPCS with this feat, and it's getting more and more frustrating when it happens.

Typically, the only mobs that have disarm are ones that spawn in huge groups. Once you lose your weapon, it tends to disappear in piles of corpses/lootbags, or be totally inaccessible because of collision models.  Occasionally, it can even glitch into the terrain if you're super unlucky and you'll need a DM to try and help you get your weapon back.    It messes up quickslots and spellslots alike if you have them, and god help you if you're a relic guardian and you lose your relic weapon. 

It's possible and the easiest solution is to make it so disarm from an NPC just puts it into your inventory, instead of the ground and this would be vastly preferred.

But this is not something that creates fun or interesting experiences on the server, unlike PC disarms which can be a huge "fuck you" but are somewhat manageable, and reasonably fair (most of the time) to deal with.
#13
Player Workshop / Regroup 2.0
October 10, 2019, 01:52:57 PM
Because regroup right now is... beyond useless for anything other than helping someone climb a cliff... I  reworked it.   DM's are free to play with the timing/VFX, but what this essentially does is cast a spell that will take just under 16 seconds to complete.

A massive, circular VFX will appear at the PC's chosen teleport location, and  nearby PCs will be able to step inside.  If they are non-hostile to the caster and remain stationary inside the circle... They are teleported to the caster's location after the spell's duration completes.

This allows you to bring allies from afar, from pre-set locations. Basically how teleport works, but in reverse.

[hide]

// Stage 1 : Creates AOE VFX, informing PC's of the teleporting
// Inform PCs that the teleport area is around them and they should move if they don't want to be zapped.
// If hostile to the caster, send a message saying they are aware of the telport but won't be grabbed
//
// Stage 2 : Similar warning, but play VFX indicating they're about to poof:
// Stage 3 : Poof the people, final VFX. LIGHT SHOW!
void PrepTarget(location lTarget, object oCaster, int nStage)
{
object oPC = GetFirstObjectInShape(SHAPE_SPHERE, 4.1, lTarget, FALSE);
effect ePrep = EffectVisualEffect(VFX_DUR_MAGIC_RESISTANCE);
effect ePrep2 = EffectVisualEffect(VFX_IMP_MAGIC_PROTECTION);
effect ePoof = EffectVisualEffect(VFX_IMP_UNSUMMON);

  while (GetIsObjectValid(oPC))
     {

        if (GetIsPC(oPC) == TRUE)
          {
            if (GetIsReactionTypeHostile(oCaster, oPC)== FALSE)
              {
                if (nStage == 1)
                 {
                 FloatingTextStringOnCreature("You feel a sense of nausea as conjurative energies flood the area around you... You sense something is trying to pull you to another place, and remaining still will allow them to do so!", oPC, FALSE);
                 }
                else if (nStage == 2)
                 {
                  FloatingTextStringOnCreature("Nausea washes over you growing increasingly intense as the conjurative energies do their work... you sense you will soon be somewhere else, unless you move!", oPC, FALSE);
                  ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ePrep, oPC, 7.0);
                  ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ePrep2, oPC);
                  SetLocalLocation(oPC, "lPreRegroup", GetLocation(oPC));
                  DelayCommand(12.0, DeleteLocalLocation(oPC, "lPreRegoup")); //cleanup
                 }
                else if (nStage == 3)
                 {
                    // Check to see if they've moved since stage 2. This will cancel the teleport.
                   if  (GetLocation(oPC) == GetLocalLocation(oPC, "lPreRegroup"))
                   {
                    ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, ePoof, GetLocation(oPC));
                    FloatingTextStringOnCreature("Nausea overwhelms you as you are conjured somewhere distant...", oPC, FALSE);
                    JumpToLocation(GetLocation(oCaster));
                   }
                   else if (GetLocation(oPC) != GetLocalLocation(oPC, "lPreRegroup") ) { FloatingTextStringOnCreature("The nausea subsides as your movement has disrupted the spell...", oPC, FALSE); }

                 }
              }

            else
              {
                // No other messaging needed. They just straight up resist if hostile.
                FloatingTextStringOnCreature("You feel a sense of nausea as conjurative energies flood the area... but make a conscious choice to resist the summoner's pull...", oPC, FALSE);

              }

          }
           oPC = GetNextObjectInShape( SHAPE_SPHERE, 4.1, lTarget, FALSE);
     }

}




void main()
{
object oPC = OBJECT_SELF;
object oTarget = GetSpellTargetObject();
location lTarget = GetSpellTargetLocation();  // Replace this with TELEPORT CONFIGURED LOCATION VARIABLE!!!


effect eVis1 = EffectVisualEffect(VFX_FNF_TIME_STOP);
effect eVis2 = EffectVisualEffect(VFX_FNF_IMPLOSION);

/*  COMPARE REGIONS, make sure lTarget is within same region! Also check for warded/teleport blocking!
   if (Region != lTargetRegion) || (region = warded)
     {
      SendMessageToPC(oPC, "The location you attempt to reach is beyond your abilities... nothing happens.");
      return;
     }
*/


/*Lock the caster into a "casting" animation for the duration here. Throw in a concentration script similar to teleport? Not going to re-invent the wheel here.
SetCommandable(FALSE)
Playanimation, etc.
CheckConcentration over duration
SetCommandable(True)
*/

ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis1, lTarget);

PrepTarget(lTarget, oPC, 1);
DelayCommand(4.0, ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis1, lTarget));
DelayCommand(6.0, PrepTarget(lTarget, oPC, 2));  // give warning, grab location to see if they've moved...
DelayCommand(8.0,ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis1, lTarget));
DelayCommand(12.0,ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis1, lTarget));
DelayCommand(12.0, PrepTarget(lTarget, oPC, 2)); // second stage2, just to give people more of a window/confirm movement
DelayCommand(15.0, ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis2, lTarget));
DelayCommand(15.8, PrepTarget(lTarget, oPC, 3));  // port the targets
}

[/hide]
#14
Bug Reports / Re: Valley of Faces QA
October 08, 2019, 11:19:27 AM
Definitely guards vs either slave slingers or slaves.  It was hectic, but slave <something> was being attacked by guards for sure.
#15
Bug Reports / Re: Valley of Faces QA
October 08, 2019, 05:10:43 AM
Small addendum :  They were also fighting outside the QA, but not all of them were. Some seemed to play nice, and others didn't