Aller au contenu

Photo

REQUEST FOR NEW IDEAS TO SCRIPT


  • Veuillez vous connecter pour répondre
96 réponses à ce sujet

#51
FunkySwerve

FunkySwerve
  • Members
  • 1 308 messages
You'd have to rewrite every spell script that used SR - not something easily fit into a neat little package for distribution. Though you might be able to halfass it with a spellhook, if you didn't care about nicities like the 'spell resisted' vfx.

Funky

Modifié par FunkySwerve, 04 décembre 2010 - 09:11 .


#52
The Amethyst Dragon

The Amethyst Dragon
  • Members
  • 1 877 messages

Vhaeraun Baenre wrote...
how about a script to make spell resistance % based instead of DC based like 2nd edition

The problem with doing this is that you'd have to alter the scripts for every spell (and possibly spell-like ability) in the game, since spell resistance checks are basically hardcoded.  Trust me, it's not a task to be taken lightly (I'm in the midst of rescripting every spell in my PW right now, and it's a big project).

Edit: And Funky beat me to the reply, I see. :P

Modifié par The Amethyst Dragon, 04 décembre 2010 - 09:14 .


#53
Vhaeraun Baenre

Vhaeraun Baenre
  • Members
  • 45 messages
yes i realize this, i would be willing to do it too if i knew what code to change/add =D

#54
FunkySwerve

FunkySwerve
  • Members
  • 1 308 messages
Well, then, it's fairly straightfoward. Edit an include name of your choosing into all the spell scripts. Do a Find/Replace on all the MyResistSpell instances, replacing them with your custom spell resistance function, named whatever you like. Then, write your custom function in the custom include you've made, keeping the same inputs as the original function:
// * Used to route the resist magic checks into this function to check for spell countering by SR, Globes or Mantles.
//   Return value if oCaster or oTarget is an invalid object: FALSE
//   Return value if spell cast is not a player spell: - 1
//   Return value if spell resisted: 1
//   Return value if spell resisted via magic immunity: 2
//   Return value if spell resisted via spell absorption: 3
int MyResistSpell(object oCaster, object oTarget, float fDelay = 0.0)

There you'll need to calculate the sr and sp of the target and caster, convert them to percentiles in whatever way you like, compare the results, and kick out the appropriate return as indicated in the original function, which you can find in NW_I0_SPELLS. Lastly, you'd probably want to edit the tlk so that item properties on your server show the proper percentile values instead of dc values.

Here's a sample replacement function, though it's still dc-based (no way to convert it without knowing what metric you intend to use). Note that it has an EXTRA input at the end, with a pre-specified default. You can add as many of those as you need to the end of your custom function, as the original functions will just get the default values applied, with you adding different values as needed. It also changed the inputs, however, something I'm not suggesting you do - we did a FAR more extensive rewrite of our spells.
int GetSpellResisted (struct SpellInfo si, object oTarget=OBJECT_INVALID, float fDelay=0.0, int bSROnly=FALSE) {
    int nSR = 0, nResisted = 0, nRoll = 0;

    if (!GetIsObjectValid(oTarget))
        oTarget = si.target;
    if (!GetIsObjectValid(oTarget))
        return 0;

    if (GetObjectType(oTarget) == OBJECT_TYPE_CREATURE)
        nSR = GetSpellResistance(oTarget);
    else
        nSR = GetLocalInt(oTarget, "SR");


    if (nSR > 0 && GetHasSpellImmunity(SPELL_SPELL_RESISTANCE, oTarget)) {
        nSR -= GetLocalInt(oTarget, "TauntResult");
        if (nSR < 1)
            nSR = 1;
    }


    if (nSR > 0 && si.sp >= 0 && !GetFactionEqual(si.caster, oTarget)) {
        nRoll = d20(1);

        if (si.sp + nRoll < nSR)
            nResisted = 1;
    }

    if (nResisted == 0) {
        if (bSROnly) {
            if (bSROnly == 2 && GetHasSpellImmunity(si.id, oTarget))
                nResisted = 2;
        } else {
            switch (ResistSpell(si.caster, oTarget)) {
                case 2:  /* globe or spell immunity */
                    nResisted = 2;
                    break;
                case 3:  /* spell mantle */
                    if (si.sp >= 0)
                        nResisted = 3;
                    break;
            }
        }
    }

    if (!nResisted) {
        if (nRoll > 0)
            SendSpellResistanceMessage(si.caster, oTarget, nRoll, si.sp, nSR, fDelay);

        return 0;
    }

    if (GetObjectType(oTarget) == OBJECT_TYPE_CREATURE) {
        effect eVis;

        switch (nResisted) {
            case 2:
                nSR  = -2;
                eVis = EffectVisualEffect(VFX_IMP_GLOBE_USE);
                break;
            case 3:
                nSR  = -3;
                eVis = EffectVisualEffect(VFX_IMP_SPELL_MANTLE_USE);
                break;
            default:
                eVis = EffectVisualEffect(VFX_IMP_MAGIC_RESISTANCE_USE);
                break;
        }

        DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
    }

    if (nRoll > 0 || nSR < -1)
        SendSpellResistanceMessage(si.caster, oTarget, nRoll, si.sp, nSR, fDelay);

    return nResisted;
}

Funky

Modifié par FunkySwerve, 05 décembre 2010 - 03:10 .


#55
cokeCan

cokeCan
  • Members
  • 15 messages
In other lisp like languages I have used a technique called code rewriting. Would that be applicable here? If you had a set of commands that need to be inserted into every spell, the script would grab the function body, rewrite-it with the extra execution and then execute the modified spell. If spells are similar enough this could save a lot of time.

#56
FunkySwerve

FunkySwerve
  • Members
  • 1 308 messages
You aren't inserting so much as replacing, so there isn't extra execution so much as changed. I'm not aware of a faster way than I described, using a text editor like UltraEdit to do mass find/replaces.



Funky

#57
WebShaman

WebShaman
  • Members
  • 913 messages
The post from worms in response to FP's is definitely the high point of this thread!

ROFL!

And in response to the "who can port this to windows?" - tbh, there are sooooo many NWNx2 scripts that really need porting to windows...*sigh*

So that is my request - please start porting NWNx2 scripts from linux to windows.

Modifié par WebShaman, 05 décembre 2010 - 02:49 .


#58
Mac-Biodiesel

Mac-Biodiesel
  • Members
  • 14 messages
Maybe this has already been done, but I'd like to control my henchman's leveling up to the same degree as I can control my own PC's. There is already a way to force a henchie to take a level in a certain class, but I'd like to also control how they spend their skill points, which feats they take, which attributes are increased, etc. For example, maybe I want my rogue henchie to pump Search, but ignore Spot.



Also, whenever I play a buffing spellcaster, I quickly lose track of what spells I've cast on myself. The effects are listed on my character sheet, but I'm not always sure what spell produce that effect.

#59
Avonos the Rogue

Avonos the Rogue
  • Members
  • 39 messages
Would it be practice to edit the nw_i0_spells MyResistSpell() directly? You could probably even fudge a defaulting extra input on a number of spells that didn't use it if so.



Vhaeraun Baenre: check out the spells.2da for HotU or whatever the most recent expansion you're building with using nwnexplorer. The 'Impact Script' column should tell you what script is associated with the spell being cast in game. From there as Funky said, trace backwards through the includes and you will find the rest of the spell system. Make sure you select 'All Resources' when you're specifying file names to open. You may need to rewrite or come up with your own functions for some of it, but it is entirely do-able.


#60
FunkySwerve

FunkySwerve
  • Members
  • 1 308 messages

Avonos the Rogue wrote...

Would it be practice to edit the nw_i0_spells MyResistSpell() directly? You could probably even fudge a defaulting extra input on a number of spells that didn't use it if so.

Actually, that's probably better still - it didn't occur to me because of my lingering bias against editing bioware includes, however outdated. The only issue I can see is that, without making any edits to the spells themselves, they'll use the default version, instead of compiling using the edited include. So, if you already have spell edits to all the scripts, this will work. Otherwise, you might as well do the mass edits.

Funky

#61
hexmendacious

hexmendacious
  • Members
  • 12 messages
I have one... how about a "Destroyable Buildings" set of scripts.  I've been tinkering with the idea for days and getting nowhere (but learning more scripting, at least).  Here's how I see such a thing:

Areas where Destroyable Buildings are available are small(ish).  Builder places a number of invisible "Attack Points" or "Foundation Stones" around the buildings.  Rather than being able to destroy just one building, the idea would be for attackers to destroy a number of buildings in an area before the destroyed version kicks in, just for practical considerations.  Builder creates copy of area  remade to be destroyed (using tileset editor and placeables). When all the attack points have been destroyed, all players in the area are transitioned to the destroyed version of the area, and a variable is set so that all area transitions TO the area now go to the Destroyed version.

All areas inside buildings that are connected to a Destroyable Area have an invisible object placed in them, too, linking them to the area that can be destroyed.  When someone attacks one of the attack points and does significant damage, players inside the buildings have their screen shake and crumbling sound play, and receive a warning that the area they are in is under attack.  If they don't get out before all the attack points have been destroyed for the linked outside area, they must make a saving throw or die (or be reduced to 1hp, or whatever). Either way (living or dead), they are then transitioned to the destroyed version of the area (outside of the building), representing their narrow escape or corpse being flung from the ruins. The Destroyed area obviously has no area transitions into the now destroyed buildings, making those areas inaccessable.  Similarly, if someone logs into a buidling that has been destroyed, a script transports them to the outside destroyed area.

Something like this would address one of the biggest problems I see with PWs - the static nature of the tilesets.  Sure it would make building more work, but I think it would be really cool.

I was playing around with the onDamaged and onDeath events of the "attack points" and the area heartbeat script to try and make it work.  Obviously, the data about what is destroyed would need to be stored in a DB so that it would remain persistant over reset.  Finally, some kind of system of 'rebuilding' could be made, so that players could restore Destroyed Areas.

Does such a thing even sound workable for multi-player, or am I just dreaming again? =]  Does anything like this already exist??

#62
ehye_khandee

ehye_khandee
  • Members
  • 855 messages
*nods* Yeah we got that too - not sure how extractable-from-the-mod it will be but I'll look.




#63
FunkySwerve

FunkySwerve
  • Members
  • 1 308 messages
I don't think destroyable buildings exist anywhere, and I can't really think of a good way to do them convincingly with tiles as opposed to placeables (I have in mind your remark about addressing the static nature of tilesets, above). We did do something similar to this, however, in a forested area, where the players were complaining about trees obstructing their view. We set the trees to be destroyable via fire spells through an area-specific spellhook.Several scorch marks and fires are spawned in randomly around the spot where the tree was. Pyromania is all in good fun, after all. :P Here's the code for the spell hook, I imagine you could do much the same with building/ruined building places and rubble:

#include "hg_inc"
#include "x2_inc_switches"

void DestroyFire (object oFire) {
    SetPlotFlag(oFire, FALSE);
    DestroyObject(oFire);
}

void DestroyTree (object oTree) {
    SetPlotFlag(oTree, FALSE);
    ApplyEffectToObject(DURATION_TYPE_INSTANT, SupernaturalEffect(EffectDeath()), oTree);
    DestroyObject(oTree, 0.5);
}

void SpawnFire (location lLoc) {
    object oObj;

    switch (Random(4)) {
        case 0: oObj = CreateObject(OBJECT_TYPE_PLACEABLE, "ph_burningcanopy", lLoc); break;
        case 1: oObj = CreateObject(OBJECT_TYPE_PLACEABLE, "ph_burningcanop2", lLoc); break;
        case 2: oObj = CreateObject(OBJECT_TYPE_PLACEABLE, "ph_burningcanop3", lLoc); break;
        case 3: oObj = CreateObject(OBJECT_TYPE_PLACEABLE, "ph_burningcanop4", lLoc); break;
    }

    DelayCommand(IntToFloat(10 + Random(20)), DestroyFire(oObj));
}

void SpawnBlaze (vector vVec) {
    object oArea = GetArea(OBJECT_SELF);
    vector vVecNew;
    location lLoc;
    int i, nFires = 2 + d4();

    for (i = 0; i < nFires; i++) {
        vVecNew = Vector(vVec.x + (Random(11) - 5), vVec.y + (Random(11) - 5), vVec.z + ((Random(11) - 5) / 10.0));
        lLoc    = Location(oArea, vVecNew, 0.0);
        SpawnFire(lLoc);
    }
}

void main() {
    int nSpellId = GetSpellId();
    float fRadius;

    switch (nSpellId) {
        case SPELL_FIREBALL:     fRadius = 20.0; break;
        case SPELL_FIRE_STORM:   fRadius = 30.0; break;
        case SPELL_FLAME_STRIKE: fRadius = 15.0; break;
        default: return;
    }

    object oTarget = GetSpellTargetObject();
    location lTarget = GetSpellTargetLocation();

    if (GetIsObjectValid(oTarget))
        lTarget = GetLocation(oTarget);

    float fDelay, fMaxDist = fRadius / 2.0;
    vector vTarget, vSpell = GetPositionFromLocation(lTarget);

    for (oTarget = GetFirstObjectInShape(SHAPE_SPHERE, fRadius, lTarget, FALSE, OBJECT_TYPE_PLACEABLE);
         GetIsObjectValid(oTarget);
         oTarget = GetNextObjectInShape(SHAPE_SPHERE, fRadius, lTarget, FALSE, OBJECT_TYPE_PLACEABLE)) {

        if (!GetPlotFlag(oTarget) || GetFortitudeSavingThrow(oTarget) < 80)
            continue;

        vTarget = GetPosition(oTarget);

        if (fabs(vTarget.x - vSpell.x) > fMaxDist || fabs(vTarget.y - vSpell.y) > fMaxDist)
            continue;

        fDelay = 1.0 + (Random(20) / 10.0);
        DelayCommand(fDelay, ApplyVisualAtLocation(VFX_FNF_FIREBALL, GetLocation(oTarget)));
        DelayCommand(fDelay + 0.2, SpawnBlaze(vTarget));

        DelayCommand(fDelay + 0.1, DestroyTree(oTarget));
    }
}


Funky

#64
TSMDude

TSMDude
  • Members
  • 865 messages
Here is some ideas i would like;

1/A set spear attack for fighters vs charging horses.

2/A way for fighters to run and charge with a weapon.

3/A way for those who shoot with thier ranged weapons into a melee have a chance to hit thier friends. (like a Area of Effect)

4/A way to make item descriptions lie.
                i.e. Cursed items

#65
TSMDude

TSMDude
  • Members
  • 865 messages
And on the destroyable, you can make any placeable flammable in our mod and we got that from the vault if I remember. We mprove don it a bit but just by adding a variable to ANY placeable you can set it on fire/destroy it with the proper spells or fire or what not.



Just do a search for flammable I think it was.

#66
Frith5

Frith5
  • Members
  • 380 messages
My flint and steel scripts do that, but so do a bunch of others, and probably better. :)

Something else I'd like, that I haven't tried to do myself:

1. The ability to interact with the nearest object specified by a chat command. ie PC walks up to a door, chats !open door, and then opens the door she's facing. I hate taking my hands off the keyboard.
This would be useful for targeting many things besides doors, of course. Such as !open chest, or !bash door, or !knock door, etc. Could use it to attack too. !kill Frith would target the object named Frith, if it exists and is in perception range, or in the area found to be right 'in front' of the calling object.

#67
Shadooow

Shadooow
  • Members
  • 4 468 messages

Frith5 wrote...

1. The ability to interact with the nearest object specified by a chat command. ie PC walks up to a door, chats !open door, and then opens the door she's facing. I hate taking my hands off the keyboard.
This would be useful for targeting many things besides doors, of course. Such as !open chest, or !bash door, or !knock door, etc. Could use it to attack too. !kill Frith would target the object named Frith, if it exists and is in perception range, or in the area found to be right 'in front' of the calling object.

You got one hand amputated?:innocent:

#68
Frith5

Frith5
  • Members
  • 380 messages
No, thank God.

I find it distracting to take my hands from the keyboard, to click a mouse. It'd be a lot faster for me to simply keep my hands on the keys and chat some commands to take the place of grabbing the mouse, targeting the door, and clicking.

My usual manner is left hand for moving about with WASDZ, my right using the arrow keys to control the camera. Thus, the desire to avoid the mouse for interacting with things, especially during RP, where the chat bar is so important to me.

Meh. Maybe I'm just so used to MUDs that I want to replicate that system here? :P

JFK

#69
hexmendacious

hexmendacious
  • Members
  • 12 messages
Thanks for the code Funky, I could use that. As for making reasonable destroyed versions - well, I'm just doing the best I can with the destroyed building City tileset options, and the many CEP NWN2 ruined buildings placeables.

#70
Bubba McThudd

Bubba McThudd
  • Members
  • 147 messages
How about a potion of "Full Manna" for mages that gives the effect of a full night's rest.

#71
Mac-Biodiesel

Mac-Biodiesel
  • Members
  • 14 messages

Bubba McThudd wrote...

How about a potion of "Full Manna" for mages that gives the effect of a full night's rest.


...and it should cost 100k gold to buy one and 5,000 XP to use it.  :P

#72
Bubba McThudd

Bubba McThudd
  • Members
  • 147 messages
Actually I was envisioning some sort of constitution penalty with a chance of permanent lowering, but yeah...

#73
jmlzemaggo

jmlzemaggo
  • Members
  • 1 138 messages
Massage in a bottle! For any caster actually, clerics, bards... also... ;-)
That is possible, I saw it twice already in modules.
A "Fountain of recuperation" I think it's called.

Modifié par jmlzemaggo, 14 décembre 2010 - 12:08 .


#74
eeriegeek

eeriegeek
  • Members
  • 47 messages
Bubba, turn on tag based scripting in your module, create a new potion item and put the following in a script. Save the script with the same name as the tag of your new potion.

#include "x2_inc_switches"

void main() {

 SetExecutedScriptReturnValue(X2_EXECUTE_SCRIPT_END);

 if (GetUserDefinedItemEventNumber()==X2_ITEM_EVENT_ACTIVATE) {
  ApplyEffectToObject(DURATION_TYPE_INSTANT,EffectVisualEffect(VFX_IMP_HEAD_MIND),GetItemActivator());

  ForceRest(GetItemActivator());

 }

}

[Edit: oops, forgot... you also have to put the "Cast Spell: Activate Item" property on your new potion!]

Modifié par eeriegeek, 14 décembre 2010 - 12:18 .


#75
jmlzemaggo

jmlzemaggo
  • Members
  • 1 138 messages
Et voilà. Nothing is NWN impossible.

The rule.



(Funny, I see I still dream about modulling again... It's like a curse. Once you got infected...)