I'm familiar with the other 3.5 sources, but they're generally setting- or area-specific. Stormwrack, for example, gives rules for pressure and cold damage, and vision (p 11). Those we handle via our enviroment scripts, but damages are going to be highly relative to the module and its power level. Vision issues are generally best solved with fog levels, though I could see maybe throwing in some conceal in extreme cases (as well as area skill mods, perhaps). Probably the most generalizable of Stormwrack's rules are a finer look at currents, but I didn't bother going into any of that, since currents are basically impossible to do correctly and unexploitably in an area where combat can happen (forcing movement requires clearing actions, which causes huge problems when trying to fight, cue actions/spells, etc). In short, I'm not aware of any other 3.5 sources readily implementable into NWN.
We considered blocking spells with verbal components underwater, but didn't - initially because of the amount of work involved, and later, because it didn't jive particularly well with the waterbreathing that was a general requirement for our underwater areas. Should you want to do something of the kind, you'll want to use
OldManWhistlers spell functions, which basically set up a number of hashes storing all kinds of info that bioware's spell scripts don't provide access to without 2da reads, indexing on spell id:
Spell Functions
by OldManWhistler
This one script provides fast access to a lot of the information stored in
SPELLS.2DA without having to use slow Get2DAString lookups.
Instead it uses local variables for storing the data at module load time so that
it can be accessed quickly at run time. It uses packed integers to store the
following spell information with only four local variables per spell:
- spell name
- spell script
- hostile setting
- feat or spell
- innate spell level
- innate spell level by class
- range
- metamagic types
- spell school
- projectile type
- immunity type
- target type
- vocal component
- somatic component
- breachable (added by Acaos)
Here are some snippets from the initialization:
void SFInitSpellNames (object oSelf) {
HashSetSetLocalString(oSelf, "SF", "SFNames_0", "Acid Fog");
HashSetSetLocalString(oSelf, "SF", "SFNames_1", "Aid");
HashSetSetLocalString(oSelf, "SF", "SFNames_2", "Animate Dead");
HashSetSetLocalString(oSelf, "SF", "SFNames_3", "Barkskin");
HashSetSetLocalString(oSelf, "SF", "SFNames_4", "Bestow Curse");
HashSetSetLocalString(oSelf, "SF", "SFNames_5", "Blade Barrier");
HashSetSetLocalString(oSelf, "SF", "SFNames_6", "Bless");
...
void SFInitSpellPack1 (object oSelf) {
HashSetSetLocalInt(oSelf, "SF", "SFPacked1_0", 0x1cbe23f2); // Acid Fog
HashSetSetLocalInt(oSelf, "SF", "SFPacked1_1", 0x0cab0ff4); // Aid
HashSetSetLocalInt(oSelf, "SF", "SFPacked1_2", 0x0cac0bf7); // Animate Dead
HashSetSetLocalInt(oSelf, "SF", "SFPacked1_3", 0x0cab0ff8); // Barkskin
HashSetSetLocalInt(oSelf, "SF", "SFPacked1_4", 0x1caa0ff8); // Bestow Curse
HashSetSetLocalInt(oSelf, "SF", "SFPacked1_5", 0x1cae87f2); // Blade Barrier
HashSetSetLocalInt(oSelf, "SF", "SFPacked1_6", 0x0caf83f4); // Bless
...
void SFInitSpellPack2 (object oSelf) {
HashSetSetLocalInt(oSelf, "SF", "SFPacked2_0", 0x07000007); // Acid Fog
HashSetSetLocalInt(oSelf, "SF", "SFPacked2_1", 0x00430303); // Aid
HashSetSetLocalInt(oSelf, "SF", "SFPacked2_2", 0x06000404); // Animate Dead
HashSetSetLocalInt(oSelf, "SF", "SFPacked2_3", 0x00303003); // Barkskin
HashSetSetLocalInt(oSelf, "SF", "SFPacked2_4", 0x05000444); // Bestow Curse
HashSetSetLocalInt(oSelf, "SF", "SFPacked2_5", 0x00000707); // Blade Barrier
HashSetSetLocalInt(oSelf, "SF", "SFPacked2_6", 0x00020202); // Bless
...
void SFInitSpellPack3 (object oSelf) {
HashSetSetLocalInt(oSelf, "SF", "SFPacked3_0", 0x0fff0800); // Acid Fog
HashSetSetLocalInt(oSelf, "SF", "SFPacked3_1", 0x0fff0004); // Aid
HashSetSetLocalInt(oSelf, "SF", "SFPacked3_2", 0x0fff0000); // Animate Dead
HashSetSetLocalInt(oSelf, "SF", "SFPacked3_3", 0x0fff0000); // Barkskin
HashSetSetLocalInt(oSelf, "SF", "SFPacked3_4", 0x0fff0801); // Bestow Curse
HashSetSetLocalInt(oSelf, "SF", "SFPacked3_5", 0x0fff0000); // Blade Barrier
HashSetSetLocalInt(oSelf, "SF", "SFPacked3_6", 0x0fff0004); // Bless
...
void SFInitSpellPack4 (object oSelf) {
HashSetSetLocalInt(oSelf, "SF", "SFPacked4_0", 0x00100401); // 1 1 1
HashSetSetLocalInt(oSelf, "SF", "SFPacked4_1", 0x00200802); // 2 2 2
HashSetSetLocalInt(oSelf, "SF", "SFPacked4_2", 0x00400005); // 4 0 5
HashSetSetLocalInt(oSelf, "SF", "SFPacked4_3", 0x00500c08); // 5 3 8
HashSetSetLocalInt(oSelf, "SF", "SFPacked4_4", 0x00001009); // 0 4 9
HashSetSetLocalInt(oSelf, "SF", "SFPacked4_5", 0x0000000b); // 0 0 11
HashSetSetLocalInt(oSelf, "SF", "SFPacked4_6", 0x0090000c); // 9 0 12
...
Those values are manipulated with shifts and masks like these:
// What is the range of the spell? (How far away can it be cast?)
const int SPELLFUNC_RANGE_LARGE = 0;
const int SPELLFUNC_RANGE_MEDIUM = 1;
const int SPELLFUNC_RANGE_SMALL = 2;
const int SPELLFUNC_RANGE_TOUCH = 3;
const int SPELLFUNC_RANGE_PERSONAL = 4; // Self-only
const int SPELLFUNC_RANGE_FOCUS = 5; // focus-based
// What can the spell be targeted against? Might be of use to some AI scripting.
const int SPELLFUNC_TARGET_SELF = 0x00000001;
const int SPELLFUNC_TARGET_CREATURE = 0x00000002;
const int SPELLFUNC_TARGET_GROUND = 0x00000004;
const int SPELLFUNC_TARGET_ITEM = 0x00000008;
const int SPELLFUNC_TARGET_DOOR = 0x00000010;
const int SPELLFUNC_TARGET_PLACEABLE = 0x00000020;
const int SPELLFUNC_TARGET_TRIGGER = 0x00000040;
// Does the spell require spoken words or gestures to cast?
const int SPELLFUNC_LOREBOOST = 0x40000000;
const int SPELLFUNC_BREACHABLE = 0x20000000;
const int SPELLFUNC_HOSTILE = 0x10000000;
const int SPELLFUNC_VERBAL = 0x08000000;
const int SPELLFUNC_SOMATIC = 0x04000000;
const int SPELLFUNC_FEAT_MASK = 0x00000001;
const int SPELLFUNC_SCHOOL_MASK = 0x0000000f;
const int SPELLFUNC_SCHOOL_SHIFT = 0x00000000;
const int SPELLFUNC_METAMAGIC_MASK = 0x0000003f;
const int SPELLFUNC_METAMAGIC_SHIFT = 0x00000004;
const int SPELLFUNC_RANGE_MASK = 0x00000007;
const int SPELLFUNC_RANGE_SHIFT = 0x0000000a;
const int SPELLFUNC_PROJECTILE_MASK = 0x00000007;
const int SPELLFUNC_PROJECTILE_SHIFT = 0x0000000d;
const int SPELLFUNC_TARGET_MASK = 0x0000007f;
const int SPELLFUNC_TARGET_SHIFT = 0x00000010;
const int SPELLFUNC_TYPE_MASK = 0x00000007;
const int SPELLFUNC_TYPE_SHIFT = 0x00000017;
const int SPELLFUNC_INNATE_SHIFT = 0x00000000;
const int SPELLFUNC_INNATE_MASK = 0x0000000f;
const int SPELLFUNC_INNATE_BD_SHIFT = 0x00000004;
const int SPELLFUNC_INNATE_BD_MASK = 0x0000000f;
const int SPELLFUNC_INNATE_CL_SHIFT = 0x00000008;
const int SPELLFUNC_INNATE_CL_MASK = 0x0000000f;
const int SPELLFUNC_INNATE_DR_SHIFT = 0x0000000c;
const int SPELLFUNC_INNATE_DR_MASK = 0x0000000f;
const int SPELLFUNC_INNATE_PA_SHIFT = 0x00000010;
const int SPELLFUNC_INNATE_PA_MASK = 0x0000000f;
const int SPELLFUNC_INNATE_RA_SHIFT = 0x00000014;
const int SPELLFUNC_INNATE_RA_MASK = 0x0000000f;
const int SPELLFUNC_INNATE_WZ_SHIFT = 0x00000018;
const int SPELLFUNC_INNATE_WZ_MASK = 0x0000000f;
const int SPELLFUNC_IDTOCAST_MASK = 0x000003ff;
const int SPELLFUNC_IDTOCAST_SHIFT = 0x00000000;
const int SPELLFUNC_IDTOIMM_MASK = 0x000003ff;
const int SPELLFUNC_IDTOIMM_SHIFT = 0x0000000a;
const int SPELLFUNC_IMMTOID_MASK = 0x000003ff;
const int SPELLFUNC_IMMTOID_SHIFT = 0x00000014;
This provides us with functions like SFGetIsSpellVerbal:
int SFGetIsSpellVerbal (int nSpell) {
return !!(HashSetGetLocalInt(GetModule(), "SF", "SFPacked1_" + IntToString(nSpell)) & SPELLFUNC_VERBAL);
}
Providing a relatively easy way to block verbal-component spells underwater, should you wish to do that, as opposed to simply blocking all spells. Nowadays, with the new 2da caching, you might well just use a 2da read, if the only thing you want to do is check for a verbal component, and you aren't worried about using too many 2da reads elsewhere (default is to store 10 in the cache, if memory serves):
Funky
Modifié par FunkySwerve, 04 juin 2011 - 01:32 .