WoR_PRC8/_module/nss/sha_subr_methds.nss
Jaysyn904 b5e28e52f4 Initial commit
Initial commit [1.18]
2025-04-03 11:49:34 -04:00

5537 lines
227 KiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
//:::::::::::::::::::::::: Shayan's Subrace Engine :::::::::::::::::::::::::::::
//::::::::::::::::::::::: File Name: sha_subr_methds :::::::::::::::::::::::::::
//:::::::::::::::::::::::::: Include script ::::::::::::::::::::::::::::::::::::
//:: Written by: Shayan
//:: Contributed to by: Moon, Parsec, TwentyOneScore :://
//:: Contact: mail_shayan@yhaoo.com :://
//:: Forums: http://p2.forumforfree.com/shayan.html
//
// ::Description: Holds all the methods used in the Subrace System. DO NOT CHANGE
// :: ANYTHING UNLESS YOU ARE CERTAIN.
// :: This is the 'core engine script'. In updates, more than likely
// :: this script is changed... so unless you do not plan to update to
// :: possible future releases of this engine, it will be in your best
// :: interest NOT to make any changes to this script. Because then you
// :: will have to redo them again.
// :: Should you disregard this warning and proceed to editing...
// :: Remember that:
// :: * If you have made a change you must recompile all scripts for
// :: changes to take place.
//
// ::Please refer to the script file 'sha_subr_consts' to change any values of the
// ::constants or default values.
// ::Version 3.0.5: Spring cleaned by Moon.
// ::Version 1.4: Reduced the numbers of local variables, by "encoding a single integer
// :: variable to hold several 'bits' of information". - Using Axe Murderer's Flag-sets.
// ::Version 1.2: Support for NWNX added.
// #include "sha_subr_consts" - Gained through sha_misc_funcs AND sha_leto_inc
//NWNX Database script.
#include "aps_include"
//NWN standard switch library.
#include "x2_inc_switches"
#include "sha_misc_funcs"
// :: Version 2.5: LETO Include functions.
#include "sha_leto_inc"
// :: Version 3.0.5b3: Made Spellhooks loading a part of the OnModLoad event
// :: Thus x2_inc_switches was required
// :: 3.0.6 removed cuz its up there a few lines ago :p
//#include "x2_inc_switches"
//::****************************************************************
// 1.69 -- Support for horses
#include "x3_inc_skin"
//::****************************************************************
//:: - ALL SUBRACE RELATED METHODS MUST BE CALLED AFTER THIS METHOD! -
//:: -- The Main function. Call this OnModuleLoad.
//
// ::Race: This is the base race that you want to create your subrace from
// :: Use ONLY: RACIAL_TYPE_ALL, or RACIAL_TYPE_DWARF, RACIAL_TYPE_ELF,
// :: RACIAL_TYPE_GNOME, RACIAL_TYPE_HALFELF, RACIAL_TYPE_HALFLING,
// :: RACIAL_TYPE_HALFORC, or RACIAL_TYPE_HUMAN.
// :: If you want to add additional races that can become part of this subrace call
// :: AddAdditionalBaseRaceToSubrace() AFTER this method.
//
// ::subrace: The subrace's name. This is what the PC will have to type in his/her
// :: Subrace field. DO NOT HAVE SPACES IN NAMES.
// :: IE: Use "Dark-elf" NOT "Dark elf".
// :: (Not case sensitive.)
//
// ::HideResRef: This is the resref of the Creature Hide/Skin you want to equip on the PC.
// :: This will have all the subrace traits like ability modifiers and base feats etc.
//
// :: If you do not want a skin, write either "none" or leave it as blank.
//
// ::UniqueItemResref: This is the resref of the item that you want given to the player. For example this item
// :: could hold can spells on it, or just description of the subrace. Ideally this item will not be droppable,
// :: and is marked as being a plot item. Regardless of what type of item this is it will be given to player when they enter the module.
// :: (If they lose it or drop it they will again get it back on the next time they enter).
//
// :: If you do not want to give the PC a unique item then, write either "none" or leave it as blank.
//
// ::IsLightSensitive: Set to TRUE if the subrace is light senstive. IE: Blinded when in Sunlight and/or gets saves and AB decreases.
// :: If the PC does not pass the fort saving throw, then it is blinded for that round.
// :: The DC for the saving throw can be changed by changing the value of
// :: LIGHT_SENSITIVE_SAVING_THROW_DC in the file sha_subr_consts. Also you can change the interval (rounds) between each time the PC
// :: is 'struk' by light by changing the value of LIGHT_BLINDNESS_STRIKES_EVERY_ROUND. And also you can change the number of rounds
// :: the PC stays blinded for if it fails the saving throw by changing tha value of LIGHT_STRUCK_BLIND_FOR_ROUNDS.
//
// :: If APPLY_AB_AND_SAVING_THROW_DECREASES_IN_LIGHT is set to TRUE, then the PC also suffers
// :: an attack bonus decrease of LIGHT_AB_DECREASE and saving throw decrease of LIGHT_SAVE_DECREASE for a number of rounds
// :: determined by: LIGHT_CAUSES_AB_AND_SAVES_DECREASE_FOR_ROUNDS.
//
// :: Rememeber: IF YOU CHANGE ANYTHING IN THE CONSTANTS FILE, IT WILL APPLY TO ALL SUBRACES.
// :: (IE: If you change the DC for the saving throw then all subraces that have light sensitivity will have to make that saving throw).
//
// ::DamageTakenWhileInLight: The amount of divine Damage the PC suffers ever round while
// :: it is in sunlight. Note: PC does not necessarily have to be Light Sensitive
// :: for this to work.
// :: If this value is negative then the PC will regenerate that amount.
//
// ::IsUndergroundSensitive: Same as IsLightSenstive but this applies when the PC is in
// :: Underground type of areas. This does not mean the PC is affected by Night time.
//
// ::DamageTakenWhileInUnderground: The amount of Negative Damage taken per round while in the Underground.
// :: Note: This too doesn't need the PC to be Under ground sensitive to apply.
// :: If this value is negative then the PC will regenerate that amount.
//
// :: ECL: Effective Character Level: Use any integer value.
// :: (For those that do not know what this is...
// :: Effective Character Level is a way of lessening your subrace's bonus abilities
// :: by reducing the amount of experience points gained per kill.)
// :: IE: If you have a Subrace with ECL of 3, then a PC (Player character) of level 10 belonging to
// :: that subrace is regarded being level 13 when gaining XP points per kill.
// :: Thus will get less experience points.
// :: NOTE: This can work for negative values as well.
//
// :: IsUndead: Mark the PC belonging to this sub-race as being Undead. It will mean that Healing spells will hurt the PC.
// :: And harming spells will heal the PC.
//
// :: PrestigiousSubrace: Mark this sub-race as being prestigious. Which means players can't become part of it when they enter in with a level 1 character with this as their chosen subrace.
// :: (Set this to TRUE, if you are making a subrace that players can become part of once they reach a certain level in another sub-race)
// :: -Refer to SetupSubraceSwitch() for more information -
//
// :: Example: You wish to create a subrace called Drow, and you have created a Creature Skin/Hide in the toolset with
// :: resref "sha_pc_drow". The Unique item (which contains spell like abilities and information about the Drow subrace)
// :: has the resref "sha_subrace_drow". And you want to make the Drow light sensitive and take 2 divine damage while in light areas.
// :: Also you would like to mark the Drow as having an Effective Character level of +1.
// :: Simply call this OnModuleLoad. (Remember to #include "sha_subr_methds", in the script)
//
// :: CreateSubrace(RACIAL_TYPE_ELF, "drow", "sha_pc_drow", "sha_subrace_drow", TRUE, 2, FALSE, 0, 1);
void CreateSubrace(int Race, string subrace, string HideResRef = "", string UniqueItemResref = "", int IsLightSensitive = FALSE, int DamageTakenWhileInLight = 0, int IsUndergroundSensitive = FALSE, int DamageTakenWhileInUnderground = 0, int ECL = 0, int IsUndead = FALSE, int PrestigiousSubrace = FALSE);
//- Add another Race that can be part of the subrace.
// :: subrace should be the same as the Subrace's name used in CreateSubrace()
// :: AdditionalBaseRace can only be RACIAL_TYPE_ALL, RACIAL_TYPE_DWARF, RACIAL_TYPE_ELF, RACIAL_TYPE_GNOME,
// :: RACIAL_TYPE_HALFELF, RACIAL_TYPE_HALFLING, RACIAL_TYPE_HALFORC, or RACIAL_TYPE_HUMAN.
void AddAdditionalBaseRaceToSubrace(string subrace, int AdditionalBaseRace);
// ::Limit the classes the PC can be, when trying to be part of this subrace.
// :: subrace should be the same as the Subrace's name used in CreateSubrace()
// :: Set the CanBe_<Class> values as desired.
//
// ::Note: This will only check PC's first class. IE: You limit your subrace's classes to only Fighter and Rogue
// :: A player with classes Wizard/Fighter/Cleric will not meet the criteria, nor will a Monk/Cleric/Rogue.
// :: Only a PC with either Rogue or Fighter as their first class will meet the requirement.
// :: IE: Rogue/WeaponMaster or Fighter/Wizard/Cleric.
void CreateSubraceClassRestriction(string subrace, int CanBe_Barbarian = TRUE, int CanBe_Bard = TRUE, int CanBe_Cleric = TRUE, int CanBe_Druid = TRUE, int CanBe_Fighter = TRUE, int CanBe_Monk = TRUE, int CanBe_Paladin = TRUE, int CanBe_Ranger = TRUE, int CanBe_Rogue = TRUE, int CanBe_Sorcerer = TRUE, int CanBe_Wizard = TRUE);
//Limit the Alignment the PC can be, when trying to be part of this subrace.
//Note this alignment restriction only applies when the PC enters the module for the first time. (A database entry is made).
// :: IE: It will not stop the PC from being part of the subrace after the PC adventures and changes in alignment.
//
// :: subrace should be the same as the Subrace's name used in CreateSubrace()
// :: Set the CanBe_<Alignment> to as desired.
void CreateSubraceAlignmentRestriction(string subrace, int CanBeAlignment_Good = TRUE , int CanBeAlignment_Neutral1 = TRUE, int CanBeAlignment_Evil = TRUE, int CanBeAlignment_Lawful = TRUE, int CanBeAlignment_Neutral2 = TRUE, int CanBeAlignment_Chaotic = TRUE);
//Use this method of Spell resistance if you want the Spell resistance to increase (or decrease) with the PC's level.
// :: subrace should be the same as the Subrace's name used in CreateSubrace()
//
// :: SpellResistanceBase: Is the vaule of SR the PC gains at level 1
// :: int SpellResistanceMax: Is the value of the SR PC gains at the maximum level achievable (default is 40, you can change the maximum level value in "sha_subr_consts")
void CreateSubraceSpellResistance(string subrace, int SpellResistanceBase, int SpellResistanceMax);
//Use this method if you want the PC's Appearance to change for the subrace.
//
// :: subrace should be the same as the Subrace's name used in CreateSubrace()
// :: AppearanceChangeTime: Time of day you want the Appearance to change.
// :: if you want to have a permanent appearance change then use: TIME_BOTH.
// :: if you want the appearance to only change when it is night time and revert back when it is day time then use: TIME_DAY.
// :: if you want the appearance to only change when it is day time and revert back to the PC's original form when it is night time then use: TIME_NIGHT.
// :: if you plan on making a controlable appearance, then set to TIME_NONE. (Refer to manual for more information)
//
// ::MaleAppearance: This is the appearance of a Male PC. Use any of the APPEARANCE_TYPE_* values.
// ::FemaleAppearance: This is the appearance of a Female PC. Use any of the APPEARANCE_TYPE_* values.
// ::Level: From which level to apply this appearance change from...
//
// ::NOTE: Not all APPEARANCE_TYPE_* constants work in standard NWN. IE: If you use APPEARANCE_TYPE_WYRMLING_BLACK, and you only have installed just NWN (no expansions),
// :: Then your appearance will be different... (in the case of wyrmiling, you will look like a mephit) - You have been warned.
void CreateSubraceAppearance(string subrace, int AppearanceChangeTime, int MaleAppearance, int FemaleAppearance, int Level = 1);
// - (You may use this twice per subrace. Once for TIME_DAY, and once for TIME_NIGHT) -
//
// Use this method if you want the PC's ability scores or AC or AB to change when it is either day or night.
// (The use of this function is slightly more complicated)
//
// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
//
// :: struct SubraceStats Stats: (Explained below)
//
// :: TimeToApply: if you want the stats/ability scores to only change when it is night time and revert back when it is day time then use: TIME_NIGHT.
// :: if you want the stats/ability scores to only change when it is day time and revert back to the PC's original stats/ability scores when it is night time then use: TIME_DAY.
//
// :: InInteriorArea: Set to TRUE if you want these changes to ability scores to happen in Interior Areas.
// :: InExteriorArea: Set to TRUE if you want these changes to ability scores to happen in Exterior Areas.
// :: InNaturalArea: Set to TRUE if you want these changes to ability scores to happen in Natural Areas.
// :: InArtifacialArea: Set to TRUE if you want these changes to ability scores to happen in Artifical Areas.
// :: InUndergroundArea: Set to TRUE if you want these changes to ability scores to happen in Underground Areas.
// :: InAbovegroundArea: Set to TRUE if you want these changes to ability scores to happen in Above Ground Areas.
//
// :: How to use this function.
//
// :: First create a structure of SubraceStats. It can be done by:
//
// :: struct SubraceStats mystats = CreateCustomeStats(<fill in appropriate values. Look at CreateCustomeStats method for more details>).
//
// :: then you want to add this to your subrace. So call
//
// :: CreateTemporaryStatModifier("mysubrace", mystats, TIME_DAY, TRUE, FALSE);
//
// ::Hence the PC belonging to "mysubrace" will have it's ability scores changed during day time, when they are in Exterior (IE: outdoors) areas.
void CreateTemporaryStatModifier(string subrace, struct SubraceStats Stats, int TimeToApply, int InInteriorArea = TRUE, int InExteriorArea = TRUE, int InNaturalArea = TRUE, int InArtifacialArea = TRUE, int InUndergroundArea = TRUE, int InAbovegroundArea = TRUE);
//This is the first half of CreateTemporaryStatModifier function.
//
//(The use of this function is slightly more complicated)
//
// :: StatModiferType: Use only SUBRACE_STAT_MODIFIER_TYPE_PERCENTAGE (if you wish to increase or decrease a PC's ability scores/AC/AB based on the percentage of the PC's current ability scores)
// :: or SUBRACE_STAT_MODIFIER_TYPE_POINTS (if you wish to increase or decrease a PC's ability scores/AC/AB by constant number.
// :: Fill in the values of the floats appropriately.
//
// ::Example: You wish to change reduce the PC's strength by 80% and increase it's dexterity by 50% and increase it's consitituion by 60%, whilst you want to increase the AC by 65%, but reduce the AB by 10%.
//
// ::so you create your stats:
//
// ::struct SubraceStats mystats = CreateCustomStats(SUBRACE_STAT_MODIFIER_TYPE_PERCENTAGE, -0.80, 0.50, 0.60, 0.0, 0.0, 0.0, 0.65, -0.10);
//
// ::You then use this in CreateTemporaryStatModifier().
struct SubraceStats CreateCustomStats(int StatModifierType, float StrengthModifier, float DexterityModifier, float ConstitutionModifier, float IntelligenceModifier, float WisdomModifier, float CharismaModifier, float ACModifier, float ABModifier);
// Restricting the use of Items (both weapons and armour) for a given subrace.
// Use this for each of the four TimeOfDay you want. (TIME_DAY, TIME_NIGHT, TIME_SPECIAL_APPEARANCE_NORMAL and TIME_SPECIAL_APPEARANCE_SUBRACE)
// ItemType should be a mix of the following (mix them by using | ):
//
// --------- Weapon Restrictions ---------
//
//
// - ITEM_TYPE_WEAPON_MELEE - Melee Weapons (incl. Monk Gloves) Does NOT include Bracers.
// - ITEM_TYPE_WEAPON_RANGED_THROW - Ranged Weapons (Throwing Weapons)
// - ITEM_TYPE_WEAPON_RANGED_LAUNCHER - Ranged Weapons (Launchers) Does "incl." Ammonition (Ammo can still be equipped but is not usable)
// - ITEM_TYPE_WEAPON_RANGED - Ranged Weapons (Both Launchers and Throwing)
// - ITEM_TYPE_WEAPON - All Weapons (Both Ranged and Melee)
//
// - ITEM_TYPE_WEAPON_PROF_SIMPLE - Simple Weapons
// - ITEM_TYPE_WEAPON_PROF_MARTIAL - Martial Weapons
// - ITEM_TYPE_WEAPON_PROF_EXOTIC - Exotic Weapons
// - ITEM_TYPE_WEAPON_PROF_ANY - All Weapon Prof.
//
// - ITEM_TYPE_WEAPON_SIZE_TINY - Tiny Weapons
// - ITEM_TYPE_WEAPON_SIZE_SMALL - Small Weapons
// - ITEM_TYPE_WEAPON_SIZE_MEDIUM - Medium Weapons
// - ITEM_TYPE_WEAPON_SIZE_LARGE - Large Weapons
//
// - ITEM_TYPE_WEAPON_SIZE_SMALL_DOWN - All Small or smaller Weapons (Small, Tiny)
// - ITEM_TYPE_WEAPON_SIZE_MEDIUM_UP - All Medium or Larger Weapons (Medium, Large)
// - ITEM_TYPE_WEAPON_SIZE_ANY - All Weapon Sizes.
//
//
//
// --------- Armour, Helm and Shield Restrictions ---------
//
// - ITEM_TYPE_SHIELD_SMALL - Small Shields
// - ITEM_TYPE_SHIELD_LARGE - Large Shields
// - ITEM_TYPE_SHIELD_TOWER - Tower Shields
// - ITEM_TYPE_SHIELD_ANY - All Shields.
//
// - ITEM_TYPE_ARMOR - Torso Armour Only (AC 0-8)
// - ITEM_TYPE_ARMOR_TYPE_CLOTH - Cloth Torso Armour only (AC 0)
// - ITEM_TYPE_ARMOR_TYPE_LIGHT - Light Torso Armour only (AC 1-3)
// - ITEM_TYPE_ARMOR_TYPE_MEDIUM - Medium Torso Armour only (AC 4-6)
// - ITEM_TYPE_ARMOR_TYPE_HEAVY - Heavy Torso Armour only (AC 7-8)
//
// - ITEM_TYPE_ARMOR_AC_0 - Torso Armour with 0 AC
// - ITEM_TYPE_ARMOR_AC_1 - Torso Armour with 1 AC
// - ITEM_TYPE_ARMOR_AC_2 - Torso Armour with 2 AC
// - ITEM_TYPE_ARMOR_AC_3 - Torso Armour with 3 AC
// - ITEM_TYPE_ARMOR_AC_4 - Torso Armour with 4 AC
// - ITEM_TYPE_ARMOR_AC_5 - Torso Armour with 5 AC
// - ITEM_TYPE_ARMOR_AC_6 - Torso Armour with 6 AC
// - ITEM_TYPE_ARMOR_AC_7 - Torso Armour with 7 AC
// - ITEM_TYPE_ARMOR_AC_8 - Torso Armour with 8 AC
//
// - ITEM_TYPE_HELM - Helms
//
// - ITEM_TYPE_FULL_ARMOR_SET - All Armours, Shields and Helms.
//
// --------- Misc. Restrictions ---------
//
// - ITEM_TYPE_JEWLERY - Rings and Amulets
// - ITEM_TYPE_MISC_CLOTHING - None-Torso clothing (Cloak, Braces, Boots) Does NOT include Jewlery
// - ITEM_TYPE_NONE_BIOWARE_ITEM - ALL None Standard Bioware Items (e.g. CEP Items)
//
//
//
// TimeOfDay should either be any mix of TIME_DAY,TIME_NIGHT, TIME_BOTH for time-based restrictions OR
// a mix of TIME_SPECIAL_APPEARANCE_SUBRACE, TIME_SPECIAL_APPEARANCE_SUBRACE for appearance-based restrictions.
// Appearance-based will override Time-based in case of conflict!
//
// Allow should be a mix of the follow constants:
// - ITEM_TYPE_REQ_ALL - Must meet ALL requirements (applies to Weapons-req. only) e.g. only weapons that are Large Weapons AND Simple Weapons can be used
// - ITEM_TYPE_REQ_ANY - Must just meet one of the requirements e.g. Large Weapons or simple weapons can be used.
// - ITEM_TYPE_REQ_DO_NOT_ALLOW - Subrace CANNOT use ItemType during TimeOfDay (input is reversed)
void SubraceRestrictUseOfItems(string subrace, int ItemType, int TimeOfDay = TIME_BOTH, int Allow = ITEM_TYPE_REQ_DO_NOT_ALLOW);
//:: Add a favored class to the subrace.
//
// (Use this only ONCE per subrace. It will not work correctly if used more than once per subrace)
// This would mean that when determining XP penalty for multiclassing, the favored
// classes do not apply when determining it (Works the same way as default NWN favored classes)
// ::(This will work ONLY if you are using the attached Shayan's XP System script).
//
//NOTE: You can use any playable base CLASS_TYPE_* constant. Do NOT USE Prestige classes,
// :: as they are not taken into consideration when determining multiclassing penalty by NWN.
// :: Also if you do specify a prestige class it will end up giving players a 20% boost to the XP gained.
// :: (Thanks to Masterlexx for spotting this bug)
void AddSubraceFavoredClass(string subrace, int MaleFavoredClass, int FamaleFavoredClass);
//Add a permanent or a temporary subrace effect on the PC, during day or night or permanently.
//
//:: subrace: Should be the same as the Subrace's name used in CreateSubrace()
//:: EffectID: There are a limited number of effects you can use here...
//:: EFFECT_TYPE_ARCANE_SPELL_FAILURE
//:: EFFECT_TYPE_BLINDNESS
//:: EFFECT_TYPE_CHARMED
//:: EFFECT_TYPE_CONCEALMENT
//:: EFFECT_TYPE_CONFUSED
//:: EFFECT_TYPE_CUTSCENEGHOST
//:: EFFECT_TYPE_HASTE
//:: EFFECT_TYPE_IMMUNITY
//:: EFFECT_TYPE_IMPROVEDINVISIBILITY
//:: EFFECT_TYPE_INVISIBILITY
//:: EFFECT_TYPE_MISS_CHANCE
//:: EFFECT_TYPE_MOVEMENT_SPEED_DECREASE
//:: EFFECT_TYPE_MOVEMENT_SPEED_INCREASE
//:: EFFECT_TYPE_POLYMORPH
//:: EFFECT_TYPE_REGENERATE
//:: EFFECT_TYPE_SANCTUARY
//:: EFFECT_TYPE_SLOW
//:: EFFECT_TYPE_TEMPORARY_HITPOINTS
//:: EFFECT_TYPE_TRUESEEING
//:: EFFECT_TYPE_ULTRAVISION
//:: EFFECT_TYPE_VISUALEFFECT
//
// :: Value1: This is the value of the first parameter (from left) that you can input for the effect.
// :: IE: If you choose EFFECT_TYPE_CONCEALMENT, which means the effect applied will be:
// :: EffectConcealment(int nPercentage, int nMissType=MISS_CHANCE_TYPE_NORMAL)
// :: Thus Value1 will be the value of nPercentage.
// :: YOU MUST INPUT A VALUE! IF NOT THE SCRIPT WILL PUT IN 0!!
//
// :: Value2: This is the value of the second parameter you can input for the effect.
// :: IE: (Refer to Value1's example) This will be the value of nMissType.
// :: YOU MUST INPUT A VALUE! IF NOT THE SCRIPT WILL PUT IN 0!!
//
// ::nDurationType: Duration type of the effect being applied...
// :: DURATION_TYPE_INSTANT, DURATION_TYPE_PERMANENT, or DURATION_TYPE_TEMPORARY.
//
// ::fDuration: The number of seconds the effect should last for...
// :: (Put 0.0 if you are making it last "forever" -IE: Whole of day time, or night time or permanetly)
//
// ::TimeOfDay: The time of day you want this applied. Use TIME_BOTH if you want this permanently applied on the PC.
//
// Use as many times as desired.
void AddSubraceEffect(string subrace, int EffectID, int Value1, int Value2, int nDurationType, float fDuration, int TimeOfDay);
//Add a different skin to the subrace at specified level. (Use as many times as desired)
//
//:: subrace: Should be the same as the Subrace's name used in CreateSubrace()
//:: SkinResRef: The Blueprint ResRef of the skin that you want the subrace to be equipped.
//:: EquipLevel: The level at which you want the skin to be applied.
//:: iTime: The time at which you want the skin to be equipped. (Use TIME_DAY, TIME_NIGHT, or TIME_BOTH.)
//
// ::Example: You want to add a skin for the subrace Illithid to use at level 15, during day time.
//
// ::Then call onModuleLoad script:
// :: AddAdditionalSkinsToSubrace("Illithid", "my_illithid_skin", 15, TIME_DAY);
//
// ::(Where "my_illithid_skin" is the resref of the skin you want equipped.)
//
// ::::
// :::: Remeber: If you say add a skin for a subrace to be equipped at level 15, then all PCs belonging to the
// :::: subrace above level 15 will also use the same skin for that time -unless you add a different skin for those levels.)
//
// ::::Use as many times as desired.
void AddAdditionalSkinsToSubrace(string subrace, string SkinResRef, int EquipLevel, int iTime = TIME_BOTH);
//::: Add equipable creature claws to the subrace. (Use as many times as desired)
//
// :: This allows you to add 'Claws' to your subrace. You simply specify the Blue print resref of
// :: the claw you want equipped on the player, and at what level.
// :: (You can use this to equip claws/slams/gore or what ever else that maybe equipped in a PC's claw item slots
//
//
//:: subrace: Should be the same as the Subrace's name used in CreateSubrace()
//:: RightClawResRef: The resref of the right hand claw. (Use "" if you do not want to specify a claw, use "none" if you want any existing right claws to be removed from the player.)
//:: LeftClawResRef: The resref of the left hand claw. (Use "" if you do not want to specify a claw, use "none" if you want any existing right claws to be removed from the player.)
//:: EquipLevel: The level at which these claws should be equipped.
//
// ::NOTE: 1. Make sure the PCs have weapon proficiency in creature weapons!!! I can't stress this enough.
// :: (Give the feat through the subrace Skin)
//
// :: 2. If you are going to use one claw, make sure it is the right claw.
//
// :: 3. Also note that you need not change both claws at once.
// :: (IE: Say you equipped a right and left claw at level 5, then say at level 10, if you want to change the left claw
// :: then you only need to specify the resref of the left claw... the PC keeps the existing right claw.)
void AddClawsToSubrace(string subrace, string RightClawResRef, string LeftClawResRef , int EquipLevel, int iTime = TIME_BOTH);
//::: Switch the player from one subrace to another ::::
//
// ::(Use only once per Level)
//
// :: This allows you to switch a player from one subrace to another.
//
//:: subrace: Should be the same as the Subrace's name used in CreateSubrace()
//:: switchSubraceName: The syntax of the subraces, you wish to switch the player (Should be the same as whatever the new subraces' name used in it's CreateSubrace())
//:: Level: The level at which this switch should take place.
//:: MustMeetRequirements: Set to FALSE, if you want the switching to bypass any class/race/alignment restriction the new subrace might have.
//
// :: If MustMeetRequirements set to TRUE, and the character fails to meet a requirement... then they will continue on as part of their current sub-race.
//
// ::IDEA: You can set the subrace you want the player to switch to as a hidden and unaccessible subrace for new characters, by setting
// :: PrestigiousSubrace to TRUE, in CreateSubrace().
// :: That way, players must earn their way to this new subrace (switchSubraceNames).
//
// ::Note: In order for this to work the subrace you wish to switch the player to does NOT have to be marked as prestigious.
//
// ::IE: If I had set up three subraces like:
// :: CreateSubrace(RACIAL_TYPE_HUMAN, "illithid", "sha_pc_illithid", "sha_subrace_illi", TRUE, 0, FALSE, 0, 3);
// :: //(Along with other setting for subrace, like class restrictions, appearance, additional skins, etc)
//
// :: CreateSubrace(RACIAL_TYPE_HUMAN, "vampire", "sha_pc_vamp001", "sha_subrace_vamp", TRUE, 2, FALSE, 0, 3, TRUE);
// :: //Can only be evil.
// :: CreateSubraceAlignmentRestriction("vampire", FALSE, FALSE, TRUE);
// :: //(Along with other setting for subrace, like class restrictions, appearance, additional skins, etc)
//
// :: CreateSubrace(RACIAL_TYPE_HUMAN, "wolkier", "sha_pc_wolk", "sha_subrace_wolk", TRUE);
// :: //Can only be Neutral;.
// :: CreateSubraceAlignmentRestriction("wolkier", FALSE, TRUE, FALSE);
// :: //(Along with other setting for subrace, like class restrictions, appearance, additional skins, etc)
//
// ::And I wished that PCs belonging to illithid be switched to vampire or wolkier at level 15, depending on which criteria they meet, then I would call:
//
// :: SetupSubraceSwitch("illithid", "vampire_wolkier", 15, TRUE);
//
// ::If I didn't want the alignment criteria to be check during switching then I would call:
//
// :: SetupSubraceSwitch("illithid", "vampire_wolkier", 15, FALSE);
//
// :: The order in which you choose the subrace to be switched is important. If the player can meet both requirements, it gives prioirty to the first one.
//
//
// :: You can put in any number of subraces to switch to..
// :: IE:
// SetupSubraceSwitch("illithid", "vampire_wolkier_pixie_shadow", 8, TRUE);
//
// If a player doesn't meet the criteria for any one of the subraces, he/she wil remain part of thier usual/current subrace.
//
// You can use SetupSwitchSubrace() as many times as you like. EG:
//
// SetupSubraceSwitch("illithid", "vampire_wolkier_pixie_shadow", 12, TRUE);
// SetupSubraceSwitch("illithid", "air-genasi_underminion", 18, TRUE);
// SetupSubraceSwitch("illithid", "mindbreaker_telephathest_darkmoon", 32, TRUE);
// SetupSubraceSwitch("illithid", "greatone", 40, FALSE);
//
// Where: vampire, wolkier, pixie, shadow, air-genasi, underminion, mindbreaker,
// telephathest, darkmoon, and greatone are all subraces.
void SetupSubraceSwitch(string subrace, string switchSubraceName, int Level, int MustMeetRequirements = TRUE);
// :: Give the player belonging to a subrace, additional unique items ::
// (Use as many times as desired for any levels)
//
// This allows you to give players belonging to a subrace additional unique items, at any level.
//
// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
// :: ItemResRef: The blueprint res-ref of the item to give.
// :: Level: The level at which to give the item.
//
// Example:
//
// Say I wanted to give my players belonging to the vampire subrace, an armour and a scythe at level 2.
// And then an amulet at level 10.
// The armor's resref is: "sha_vamp_arm"
// The scythe's resref is: "sha_vamp_scythe"
// The amulet's resref is: "sha_vamp_ammy"
//
// So I simply call:
// AddSubraceItem("vampire", "sha_vamp_arm", 2);
// AddSubraceItem("vampire", "sha_vamp_scythe", 2);
// AddSubraceItem("vampire", "sha_vamp_ammy", 10);
//
//// NOTE: You can only give ONE item of each. IE: You CAN'T do this expecting to give 2 amulets:
//
// AddSubraceItem("vampire", "sha_vamp_ammy", 10);
// AddSubraceItem("vampire", "sha_vamp_ammy", 10);
void AddSubraceItem(string subrace, string ItemResRef, int Level = 1);
// :: Setup an alias for your subrace.
//
// Allows you to use two or more "names" for the same subrace without
// having to add it twice.
//
// See SSE_TREAT_ALIAS_AS_SUBRACE in sha_subr_consts for more info.
void SetupSubraceAlias(string subrace, string Alias);
// :: Setup a Prestige class restriction for a 'Prestige' subrace.
//
// NOTE: This will only be checked during a 'subrace switch' for obvious reasons. Refer to SetupSubraceSwitch(...)
//
// subrace = Should be the same as the Subrace's name used in CreateSubrace().
// MinimumLevels = The minimum number of levels in a/any particular prestigious class allowed to pass the restriction.
// Set CanBe_<Class> values as desired.
//
// Example:
//
// Say I have a subrace 'Phantasm' and I wanted to add a restriction so that only Shadow Dancers, Blackguards, and Assasin can be part of.
// AND they must have atleast 5 levels in any of those classes.
// So I set:
//
// CreateSubracePrestigiousClassRestriction("phantasm", 5, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE);
//
// * A player with class combination like <Any base class>/Assasin(2)/ShadowDancer(3) will meet this criteria.
//
// NOTE: This can be used in combination with CreateSubraceClassRestriction(...)
//
// If you wanted to you can also set-up a primary/base class restriction with CreateSubraceClassRestriction(...) and also create a Prestigious class restriction with this.
void CreateSubracePrestigiousClassRestriction(string subrace, int MinimumLevels = 1, int CanBe_ArcaneArcher = TRUE, int CanBe_Assasin = TRUE, int CanBe_Blackguard = TRUE, int CanBe_ChampionOfTorm = TRUE, int CanBe_RedDragonDisciple = TRUE, int CanBe_DwarvenDefender = TRUE, int CanBe_HarperScout = TRUE, int CanBe_PaleMaster = TRUE, int CanBe_ShadowDancer = TRUE, int CanBe_Shifter = TRUE, int CanBe_WeaponMaster = TRUE, int CanBe_PurpleDragonKnight = TRUE);
// :: Add wings or tail to the subrace ::
//
// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
// :: Male_Wings: The wing to be added for a male character: Use any APPEARANCE_TYPE_ATTACHMENT_WINGS_* constant.
// :: Female_Wings: The wing to added for a female character: Use any APPEARANCE_TYPE_ATTACHMENT_WINGS_* constant.
// :: Male_Tail: The tail to be added for a male character: Use any APPEARANCE_TYPE_ATTACHMENT_TAIL_* constant.
// :: Female_Tail: The tail to be added for a female character: Use any APPEARANCE_TYPE_ATTACHMENT_TAIL_* constant.
// :: Level: The level at which to add these attachments.
// NOTE: If you are using any of the CEP tails or wings, your server/module must have CEP.
//
// Example of Usage:
//
// Say I want to add bird like wings to the male character, and angel wings to the female character at level 21:
// I also want to change the male wings to devil and the female to red dragon disciple's, and add a bone tail to both genders at level 36.
//
//
// AddSubraceAppearanceAttachment("mysubrace", APPEARANCE_TYPE_ATTACHMENT_WINGS_BIRD, APPEARANCE_TYPE_ATTACHMENT_WINGS_ANGEL, 0, 0, 21);
// AddSubraceAppearanceAttachment("mysubrace", APPEARANCE_TYPE_ATTACHMENT_TAIL_DEVIL, APPEARANCE_TYPE_ATTACHMENT_WINGS_RED_DRAGON_DISCIPLE, APPEARANCE_TYPE_ATTACHMENT_TAIL_BONE, APPEARANCE_TYPE_ATTACHMENT_TAIL_BONE, 36);
//
//
//:: You may use this as many times as desired.
void ModifySubraceAppearanceAttachment(string subrace, int Male_Wings = 0, int Female_Wings = 0, int Male_Tail = 0, int Female_Tail = 0, int Level = 1);
// :: Use to restrict subrace's gender ::
//
// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
// :: CanBeMale: Set to FALSE if you do not want the subrace to be playable by Male characters
// :: CanBeFemale: Set to FALSE if you do not want the subrace to be playable by Female characters
//
// :: Example of useage:
// Say I want my subrace "Pixie" only be playable by Female characters... then I would call:
//
// CreateSubraceGenderRestriction("pixie", FALSE, TRUE);
void CreateSubraceGenderRestriction(string subrace, int CanBeMale = TRUE, int CanBeFemale = TRUE);
// :: Use to the portrait of a character ::
//
// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
// :: MalePortrait: Set the name of the male portrait.
// :: FemalePortrait: Set the name of the female portrait.
// :: Level: The level at which to change the portrait.
//
// List of portraits' file names can be found in portraits.2da.
//
// NOTE: This function will correclty set the portraits. But whether or not other players or the player him/herself can see
// it depends on whether they have portrait in their portrait folder or the expansion packs containing the portraits.
// (Like in the below for example: The Queen Shao's portrait is only included in HoTU. So if the player does not have Queen Shao's portraits in his/her
// portrait folder will not be able to see them. And other players without HoTU will not be able to see the player's portrait)
//
// NOTE 2: If you want to use any of the standard portraits (That is any from NWN) make sure you have "po_" as prefix.
// IE: If you want to use the portrait set 'el_f_04_' (as listed in portraits.2da) the actual name is: po_el_f_04_.
// (Some portraits in the standard library do not use the po_ prefix... and there is no way to tell other than by trial and error)
//
// Example of Useage:
// Say I have the Queen Shao's portraits. These portraits are po_queenshao_h, po_queenshao_l, po_queenshao_m, po_queenshao_s, and po_queenshao_t.
// So this means that this portrait set is refered to by: po_queenshao_
// Likewise say I have another portrait set: my_male_port_
//
// And say I want to set Queen Shao's portrait to all the female players, and my other portrait set to the male characters
// at level 6. So I would call:
//
// ChangePortrait("mysubrace", "my_male_port_", "po_queenshao_", 6);
//
// :: You may use this as many times as desired.
void ChangePortrait(string subrace, string MalePortrait, string FemalePortrait, int Level = 1);
// :: Use to set-up an automated change in the subrace's faction ::
//
// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
// :: FactionCreatureTag: The tag of the creature whose perception of the subrace will be adjusted.
// :: Reputation: Use any SUBRACE_FACTION_REPUTATION_* constants.
//
// Refer to the .PDF Guide book for a detailed example, and implementation of this function.
//
// Example of function usage:
//
// Say I have a NPC faction called 'Drow Faction'. This faction will normally attack
// (Hostile) player character. But I want to have the players belonging to the 'Drow' subrace
// be treated friendly, by the NPCs belonging to this faction...
//
// So inorder to do this; first I will need to create:
// An NPC in a LOCKED room (IE: no player can enter), I would remove all weapons and items from this
// NPC.
// Set it as Immortal (NOT Plot).
// Set it's tag to say: MY_DROW_FACTION_NPC
// And then call this function:
//
// ModifySubraceFaction("drow", "MY_DROW_FACTION_NPC", SUBRACE_FACTION_REPUTATION_FRIENDLY);
void ModifySubraceFaction(string subrace, string FactionCreatureTag, int Reputation = SUBRACE_FACTION_REPUTATION_HOSTILE);
// :: Setup a start location for a subrace ::
//
// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
// :: WaypointTag: The Tag of the waypoint to which the player will be ported to.
//
//
// This will teleport the player belonging to the Subrace 'subrace' to
// the waypoint, when they enter the module.
void CreateSubraceStartLocation(string subrace, string WaypointTag);
//3.0.6.4
// :: Setup a death location for a subrace ::
//
// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
// :: WaypointTag: The Tag of the waypoint the player will be teleportd to.
//
//
// This will teleport the player belonging to the Subrace 'subrace' to
// the waypoint, when they respawn after death.
void CreateSubraceDeathLocation(string subrace, string WaypointTag);
// 3.0.6.6 - Not just for leto anymore...
// :: Use to setup different skin and hair colors for subrace ::
//
// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
// :: Male_Hair: which color male hair is to be set to.
// :: Female_Hair: which color female hair is to be set to.
// :: Male_Skin: which color male skin is to be set to.
// :: Female_Skin: which color male skin is to be set to.
// :: Level: the level at which this change is to take place.
//
// Written by: TwentyOneScore
void ModifySubraceAppearanceColors(string subrace, int Male_Hair = -1, int Female_Hair = -1, int Male_Skin = -1, int Female_Skin = -1, int Level = 1);
//3.0.6.6
// :: Use to setup different eye colors for subrace ::
//
// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
// :: Male_Eye: which color male eyes is to be set to.
// :: Female_Eye: which color female eyes is to be set to.
// :: use any SSE_EYE_COLOR_* constant
void SHA_ModifySubraceEyeColors(string subrace, int Male_Eyes = -1, int Female_Eyes = -1, int Level = 1);
//3.0.6.9
// :: Use to setup specific heads for subrace ::
//
// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
// :: Male_Head: which head male is to be set.
// :: Female_Head: which head female is to be set.
void ModifySubraceHead(string subrace, int Male_Head = -1, int Female_Head = -1, int Level = 1);
//:: ----- LETO FUNCTION DEFINERS -------
// :: Add/remove a feat to/from the character belonging to a subrace ::
//
// >>> NEEDS LETO TO WORK (REFER TO THE MANUAL FOR MORE DETAILS)
//
// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
// :: FeatID: Use any FEAT_* constants.
// :: Remove: If set to TRUE, it will remove the the feat from the player.
// :: Level: Level at which to give this bonus feat.
//
// NOTE: Player must have the required expansion packs for the feats. IE: If you were to give Epic Dodge,
// the player must have HoTU expansion pack installed inorder to recieve/use the feat.
//
// Example of Usage:
//
// Say I want to give Disarm at level 5, and improved knockdown at level 8 to the players belonging to Drow subrace.
// I also want to remove Alterness from the player at level 10.
//
// ModifySubraceFeat("drow", FEAT_DISARM, 5);
// ModifySubraceFeat("drow", FEAT_IMPROVED_KNOCKDOWN, 8);
// ModifySubraceFeat("drow", FEAT_ALERTNESS, 10, TRUE);
//
//:: You may use this as many times as desired.
void ModifySubraceFeat(string subrace, int FeatID, int Level = 1, int Remove = FALSE);
// :: Create custom base stats::
//
// >>> NEEDS LETO TO WORK (REFER TO THE MANUAL FOR MORE DETAILS)
//
// :: This is used in conjunction with CreateBaseStatModifier(...) -refer to it for more details.
//
// :: --- Fill in the Modifiers as desired.
// For speed modification use any MOVEMENT_SPEED_* constant.
//
// Example: I want to increase Strength by 6, decrease Dexterity by 4, increase Consitution by 4, and change the movement speed to fast.
// So I would call:
//
// struct SubraceBaseStatsModifier MyStats = CustomBaseStatsModifiers(6, -4, 4, 0, 0, 0, MOVEMENT_SPEED_FAST);
struct SubraceBaseStatsModifier CustomBaseStatsModifiers(int StrengthModifier, int DexterityModifier, int ConstitutionModifier, int IntelligenceModifier, int WisdomModifier, int CharismaModifier, int MovementSpeedModifier);
// :: Use to make PERMANENT changes to the ability scores or movement speed of the character::
//
// >>> NEEDS LETO TO WORK (REFER TO THE MANUAL FOR MORE DETAILS)
//
// :: This is used in conjunction with SubraceBaseStatsModifier CustomBaseStatsModifiers(...)
//
// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
// :: SubraceBaseStatsModifier Stats: Use CustomBaseStatsModifiers(...) to create the stats.
// :: Level: The level at which to make these changes.
// :: Set: If you set it to TRUE, then these stats will REPLACE (instead of adding or subtracting) the player's stats.
//
//
// Example of Useage:
// Say I have a subrace called: black-dragon.
// And I want to increase Strength by 6, decrease Dexterity by 4, increase Consitution by 4,
// and decrease charisma by 2, and change the movement speed to fast at level 10.
//
// So I would call:
//
// struct SubraceBaseStatsModifier MyStats = CustomBaseStatsModifiers(6, -4, 4, 0, 0, -2, MOVEMENT_SPEED_FAST);
// CreateBaseStatModifier("black-dragon", MyStats, 10);
//
// :: You may use this as many times as desired.
void CreateBaseStatModifier(string subrace, struct SubraceBaseStatsModifier Stats, int Level = 1, int Set = FALSE);
// :: Use to the soundset of the character ::
//
// >>> NEEDS LETO TO WORK (REFER TO THE MANUAL FOR MORE DETAILS)
//
// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
// :: MaleSoundSet: Refer to the table in the PDF guide book and enter the 'Reference Number'.
// :: FemaleSoundSet: Refer to the table in the PDF guide book and enter the 'Reference Number'.
// :: Level: The level at which to change the soundset.
//
// Example of Useage:
// Say I want to change the Male character's soundset to Minotaur, Chief and the Female character's
// soundset to Succubusat level 16. And then at level 25 change it to Ogre and Nymph.
// >>> According to the table in the PDF guide book the numbers are 65 for Minotaur Chief, 90 for the Succubus,
// 70 for Ogre, and 197 for the Nymph soundsets).
//
// ChangeSoundSet("mysubrace", 65, 90, 16);
// ChangeSoundSet("mysubrace", 70, 197, 25);
//
// :: You may use this as many times as desired.
void ChangeSoundSet(string subrace, int MaleSoundSet, int FemaleSoundSet, int Level = 1);
// :: Modify a skill a character belonging to a subrace has ::
//
// >>> NEEDS LETO TO WORK (REFER TO THE MANUAL FOR MORE DETAILS)
//
// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
// :: SkillID: Use any SKILL_* constants.
// :: iModifier: The value to increase or decrease or set the skill by/to.
// :: Set: If set to TRUE, the skill points in the chosen skill will be set to the value of iModifier.
//
// Example of Usage:
//
// Say I want to increase Spot skill by 15, and decrease Search by 12 at level 10, and set Tumble to 5 at level 16.
// I would call:
//
// ModifySubraceSkill("mysubrace", SKILL_SPOT, 15, 10);
// ModifySubraceSkill("mysubrace", SKILL_SEARCH, -12, 10);
// ModifySubraceSkill("mysubrace", SKILL_TUMBLE, 5, 16, TRUE);
void ModifySubraceSkill(string subrace, int SkillID, int iModifier, int Level = 1, int Set = FALSE);
// :: Use to setup a special subrace restriction
//
// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
// :: Type: The type of special restriction (e.g. item, variable etc) See SUBRACE_SPECIAL_RESTRICTION_*
// :: VarName: The variable name if a variable or the tag if item (etc.)
// :: Existance: if TRUE then this variable/item must exist, if FALSE it must not exist.
// :: Database: The name of the database or the tag of the item, which holds the variable (not used for "must have item"-restriction).
// :: if Database is empty it will default to SUBRACE_DATABASE (if Database) or the Player (if Local var)
//
// Written by: Moon
void CreateSubraceSpecialRestriction(string subrace, int Type, string VarName, int Existance=TRUE, string Database="");
/*
:::::::::::::::::::::::: Function Definers usuable anywhere ::::::::::::::::::::
*/
//:: You may use these functions anywhere, and they would work appropriately.
// ::Erases all "temporary" subracial abilities, so that after respawn or a restoring spell is cast
// ::the heartbeat script will then reapply the stats again.
void ReapplySubraceAbilities(object oPC);
//Add this on the Module OnClientEnter script.
void SubraceOnClientEnter(object oPC = OBJECT_INVALID);
//Add this to Module OnPlayerRespawn script.
void SubraceOnPlayerRespawn();
//Add this to Module OnPlayerLevelUp script.
void SubraceOnPlayerLevelUp();
//Add this to Module OnPlayerEquipItem script.
void SubraceOnPlayerEquipItem();
//Add this to the Module OnItemActivated script.
void SubraceOnItemActivated();
//Subrace Heartbeat function - For use in default.nss
void SubraceHeartbeat(object oPC = OBJECT_SELF);
//Add this to the Module OnClientLeave script.
void SubraceOnClientLeave();
//:: Returns TRUE if SSE has been disabled serverwide.
//:: This check does NOT care if SSE has been disabled in the current area.
int GetIsSSEDisabled();
//:: Returns TRUE if SSE has been disabled in Area.
//:: This check does NOT care if SSE has been disabled Serverwide.
//:: returns FALSE on error (e.g. if input is non an area)
int GetIsSSEDisabledInArea(object Area);
//:: Returns SSE_STATUS_OPERATIONAL if SSE is running properly.
//:: Else it returns a flag depending on the issue.
//:: See SSE_STATUS_* constants. It adds all that applies.
//:: If a non-valid area is supplied, area check is skipped.
int GetSSEStatus(object Area=OBJECT_INVALID);
//:: Force the player to properly un-equip the item.
void SHA_SubraceForceUnequipItem(object oItem);
//:: Force the player to properly equip oItem in the inventory slot: InvoSlot.
void SHA_SubraceForceEquipItem(object oItem, int InvoSlot);
//Return the XP modifier for being part of the Subrace
//(Calclates modifer value for Subrace Favored classes)
float GetSubraceXPModifier(object oPC);
//:: Returns TRUE if the player is marked as being part of an undead subrace.
//:: Returns FALSE if player is not an undead OR provided character is NOT a PC!
//:: (Shayan's Subrace Engine)
int Subrace_GetIsUndead(object oPC);
//:: Returns the Effective Character level of oPC.
//:: (Shayan's Subrace Engine)
int GetECL(object oPC);
//:: Deletes every bit of subracial information stored on the PC. Also destroys equipped skins and claws.
//:: Set ClearSubraceField to TRUE if you wish, to have their Subrace field cleared (set to "") after this is done.
//:: If you don't SSE will assume they are new to the subrace and re-initiate them to the subrace at next login (assuming they still meet the demands)
//:: (Shayan's Subrace Engine)
void DeleteSubraceInfoOnPC(object oPC, int ClearSubraceField=FALSE);
//:: Change the PC to his/her default humaniod appearance.
//:: IE: If the player is human and his/her appearance is Illithid, this will turn them back
//:: to looking like human again.
//:: (Shayan's Subrace Engine)
void ChangeToPCDefaultAppearance(object oPC);
//:: Returns TRUE if PC belongs to a subrace which is Light sensitive.
//:: (Shayan's Subrace Engine)
int GetIsPCLightSensitive(object oPC);
//:: Return the Favored class of the PC. Returns -1 if there is none.
//:: (Shayan's Subrace Engine)
int Subrace_GetFavouredClass(object oPC);
//:: Send's a message to PC, with a Subrace Engine title. Set Important to TRUE if
//:: it is an important message. (Refer to sha_subr_consts for more info.)
//:: (Shayan's Subrace Engine)
void SHA_SendSubraceMessageToPC(object oPC, string message, int Important = TRUE);
//:: Send's a message to PC with a Subrace Engine title. This will follow the new
//:: message standards and allow very selective messages. If you wish to use this
//:: for non-standard-SSE messages, MessageReference should be MESSAGE_USER_MADE.
//:: VariableText will then be directly displayed (With Subrace Engine title)
//::
//:: MessageType must contain the MESSAGE_TYPE_* constants, for user made messages!
//::
//:: NOTE: MESSAGE_TYPE_VITAL will ALWAYS be displayed REGARDLESS of settings and
//:: MESSAGE_TYPE_LOG will ALWAYS be logged! (Assuming there is a message to send/log)
//::
//::
//:: (Refer to the manual or sha_subr_consts for more info.)
//:: (Shayan's Subrace Engine)
void SSE_MessageHandler(object Receiver, int MessageReference, string VariableText="", string VariableText2="", int MessageType = MESSAGE_TYPE_DEFAULT);
//:: Traverses through oPC's inventory, destroying all Skins, and creature items.
void SearchAndDestroySkinsAndClaws(object oPC);
//:: Removes temporary subrace ability scores and AB boosts.
void ClearSubraceEffects(object oPC);
//:: Returns TIME_DAY, or TIME_NIGHT depending on the current hour of day.
int SHA_GetCurrentTime();
//:: Returns the default appearance type of oPC. (It ignores any appearance
//:: change by SetAppearance()).
//:: NOTE: oPC must be a player character in order for this to work.
int SHA_GetDefaultAppearanceType(object oPC);
//:: This will load scripts containing sub-races. You can use the Conditions parameter
//:: if you want to make the script load only if Leto is (or is not) enabled.
void LoadSubraceFromScript(string Script, int Conditions=SSE_SUBRACE_LOADER_CONDITION_ALWAYS_LOAD);
// :: Switch oTarget's subrace to Subrace
// :: Note this function does not do any checking, to see if oTarget meets
// :: any alignment or race criteria. Should be used with caution.
// :: Takes approximately 12 - 15 seconds to complete.
void ApplySubrace(object oTarget, string Subrace);
// :: Use this on the OnModuleLoad script to signal that the subraces has been loaded
// :: and we are good to go. If you do not call this one, SSE will wait forever!
// :: It has an internal delay and will wait up 30 seconds for other sub-race scripts to load.
// :: NOTE! After the first sub-race load has been detected, further 5 seconds are given to finish
// :: the loading. After that SSE will not wait any further!
// :: It is adviced to have all your subraces load within 5 seconds of each other!
// :: (If you use LoadSubraceFromScript(), you do not have to worry about this)
// ::
// :: doNWNXInit is used to call the NWNX Init "NWNX!INIT" with parameter "1".
// :: set to TRUE if you do not have an external call to it and plan on using NWNX (Leto or NWNX database)
void SSE_ModuleLoadEvent(int doNWNXInit=FALSE);
// :: Use this to get the base race of the alias.
// :: if Alias is the base race then it returns itself.
// :: returns "" if the Alias is not valid/no such subrace exist
// :: if Lowercase is TRUE it will return a lowercased string
string GetSubraceNameByAlias(string Alias, int Lowercase=FALSE);
// :: Use this to get the race name of the ID.
// :: returns "" if the Alias is not valid/no such subrace exist
// :: if Lowercase is TRUE it will return a lowercased string
string GetSubraceNameByID(int ID, int Lowercase=FALSE);
// :: Returns the Player's Subrace ID.
int GetPlayerSubraceID(object Player);
//This will add MessageType too the list of message types that is SSE may display
//If no list is present, a new (empty) list will be created and the type will be added to it.
//NOTE: Vital will ALWAYS be displayed and Log will ALWAYS be logged!
void SSE_Message_AddDisplayType(int MessageType);
//This will remove MessageType from the list of message types that is SSE may display
//If no list is present, it is assumed you want to use the server default without this type!
//NOTE: Vital will ALWAYS be displayed and Log will ALWAYS be logged!
void SSE_Message_RemoveDisplayType(int MessageType);
//Creates a new list of the Message types SSE that is allowed to display with MessageType as an entry
// the old list will be deleted.
//NOTE: Vital will ALWAYS be displayed and Log will ALWAYS be logged!
void SSE_Message_SetDisplayType(int MessageType);
//returns the list of message types SSE is allowed to display.
//if no list is present, MESSAGE_TYPE_SERVER_DEFAULT or FALSE will be returned depending on DoNotReturnServerDefault
int SSE_Message_GetDisplayType(int DoNotReturnServerDefault=FALSE);
//3.0.6
// Adds horse Menu Feat to Hide of oPC
void SSE_HorseAddHorseMenu(object oPC);
// :: 3.0.6.5
// - Activate Spell-Like Ability
//
// oPC : Ability user
//
// AbilityUsed : SPELL_*, SPELLABILITY_*, or # from spells.2da
//
// oTarget : Ability subject, if not provided oPC is target
//
void SubraceAbility(object oPC, int AbilityUsed, object oTarget = OBJECT_SELF);
// - Replaces subrace value of "" with SUBRACE_*_DEFAULT
// if USE_SSE_DEFAULT_RACES = TRUE
void CheckAndApplyDefaultSubrace(object oPC);
// - Returns oPC's subrace death location Waypoint
object GetSubraceDeathWaypoint(object oPC);
// - Returns oPC's subrace death location Waypoint
object GetSubraceStartWaypoint(object oPC);
// - Move oPC to subrace's death location or defaults
void Subrace_MoveToDeathLocation(object oPC);
//3.0.6.6
// Gives oPC it's subraces's hair and/or skin color
void ApplySubraceColors(object oPC);
// Gives oPC it's subraces's glowing eyes
void ApplySubraceEyeColors(object oPC);
// Gives oPC glowing eyes, use any SSE_EYE_COLOR_* const
void SHA_SetEyeColor(object oPC, int iEyes = -1);
//3.0.6.9
// Gives oPC it's subraces's head
void ApplySubraceHead(object oPC);
//
//::::::::::::::::::::::::: Interal Function definers:::::::::::::::::::::::::::
//
// :: Do not use these functions outside this script. They may not work correctly.
string SSE_GetStandardMessage(int Ref, string VariableText="", string VariableText2="");
void SaveSubraceOnModule(struct Subrace shaSubrace);
void GiveSubraceUniqueItem(string SubraceStorage, object oPC);
void SaveSubraceAlignmentRestrictionOnModule(struct SubraceAlignmentRestriction shaSubraceAlignRes);
void SaveSubraceClassRestrictionOnModule(struct SubraceClassRestriction shaSubraceClassRes);
void SaveSubraceSpellResistanceOnModule(struct SubraceSpellResistance shaSubraceSpellRes);
void SaveSubraceAppearanceChangeOnModule(struct SubraceDifferentAppearance shaSubraceApp);
int CheckIfPCMeetsClassCriteria(object oPC, string SubraceStorage);
int CheckIfPCMeetsAlignmentCriteria(object oPC, string SubraceStorage);
int CheckIfPCMeetsAnySubraceCriteria(object oPC);
int CheckIfPCMeetsSpecialCriteria(object oPC, string SubraceStorage);
void SHA_ApplyTemporaryStats(object oPC, string SubraceStorage, int iCurrentTime, int iTime, int AreasReq/*int AreaUndAbove, int AreaIntExt, int AreaNatArt*/);
void ApplyTemporarySubraceStats(object oPC, string SubraceStorage, int iCurrentTime, int AreaUndAbove, int AreaIntExt, int AreaNatArt);
void ApplyStat_AbilityByPercentage(int AbilityToMod, float percentage, object oPC);
void ApplySubraceBonusStatsByPercentage(object oPC, string SubraceStorage);
void ApplyAttackBonusByPercentage(float percentage, object oPC);
void ApplyArmourClassBonusByPercentage(float percentage, object oPC);
void ApplySubraceBonusStatsByPoints(object oPC, string SubraceStorage);
void ApplyStat_AbilityByPoints(int AbilityToMod, float points, object oPC);
void ApplyAttackBonusByPoints(float points, object oPC);
void ApplyTemporarySubraceAppearance(string SubraceStorage, object oPC, int iCurrentTime);
void ApplyArmourClassBonusByPoints(float points, object oPC);
void ClearSubraceTemporaryStats(object oPC);
void LoadSubraceInfoOnPC(object oPC, string subrace);
void ApplyPermanentSubraceSpellResistance(int ID, object oPC);
void InitiateSubraceChecking(object oPC);
int GetFavoredClassExceedsGap(int Race1Favored, int Race2Favored, int Class1, int Class2, int Class3, int Class13Gap, int Class23Gap, int Class12Gap);
void ApplySubraceEffect(object oPC, string SubraceStorage, int TimeOfDay);
void CheckIfCanUseEquipedWeapon(object oPC);
void EquipTemporarySubraceClaw(string SubraceStorage, object oPC, int iTime);
void EquipTemporarySubraceSkin(string SubraceStorage, object oPC, int iTime);
void CheckAndSwitchSubrace(object oPC);
void SubraceCheckItemActivated(object oPC, string sTag);
string Subrace_TimeToString(int iTime);
int CheckIfPCMeetsPrestigiousClassCriteria(object oPC, string SubraceStorage);
int CheckForLetoReLog(object oPC, int Level);
string CheckAndModifyBaseStats(object oPC, string SubraceStorage, int Level);
string CheckAndModifySkills(object oPC, string SubraceStorage, int Level);
string CheckAndModifyFeats(object oPC, string SubraceStorage, int Level);
string CheckAndModifySoundSet(object oPC, string SubraceStorage, int Level);
void DelayBoot(object oPC);
void Subrace_FactionAdjustment(object oPC, string FactionTag, int Adjustment);
void ChangeSubraceFactions(object oPC, string SubraceStorage);
void Subrace_MoveToStartLocation(object oPC, string subrace = "");
void SetSubraceDBInt(string sCampaignName, string sVarName, int nInt, object oPlayer=OBJECT_INVALID);
int GetSubraceDBInt(string sCampaignName, string sVarName, object oPlayer=OBJECT_INVALID);
void DeleteSubraceDBInt(string sCampaignName, string sVarName, object oPlayer);
void DeleteSubraceInfoInDatabase(object oPC, string subrace);
void CheckIfCanUseEquippedArmor(object oPC);
void ApplyPermanentSubraceAppearance(int ID, object oPC);
void ChangeMiscellaneousSubraceStuff(object oPC, int Level);
void ModifyAttachments(object oPC, string SubraceStorage, int Level);
//Memory handling - Added in 3.0.5
int GetSSEInt(string VariableName);
void DeleteSSEInt(string VariableName);
void SetSSEInt(string VariableName, int Value);
int GetSubraceID(string subrace);
void SetSubraceID(string subrace, int Value);
string GetSubraceStorageLocationByID(int SubraceID);
string GetSubraceStorageLocation(string subrace);
//::****************************************************************
// 1.69 -- Returns TRUE if oSkin is valid and has the Horse Menu Feat on it. Returns FALSE otherwise.
int GetSkinHasHorseMenu( object oSkin);
//::****************************************************************
//:: ---------------------------------------------------------------------------
//:: Functions for the Subrace Engine.
//:: ---------------------------------------------------------------------------
//Data is stored on the module for easy central access.
object oStorer = GetModule();
/*
::::::::::::::::::::::::::: Function definers ::::::::::::::::::::::::::::::::::
*/
// :: Below lies the list of all the functions useable OnModuleLoad to setup
// :: a subrace.
//3.0.6.5
void SubraceAbility(object oPC,int AbilityUsed,object oTarget = OBJECT_SELF)
{
AssignCommand(oPC, ClearAllActions());
if (oTarget == OBJECT_INVALID) oTarget = oPC;
AssignCommand(oPC,ActionCastSpellAtObject(AbilityUsed,oTarget,METAMAGIC_NONE,TRUE,0,PROJECTILE_PATH_TYPE_DEFAULT,TRUE));
}
object GetSubraceStartWaypoint(object oPC)
{
string SubraceStorage = GetSubraceStorageLocation(GetSubRace(oPC));
string WPTag = GetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_START_LOCATION);
object oWP = GetWaypointByTag(WPTag);
return oWP;
}
object GetSubraceDeathWaypoint(object oPC)
{
string SubraceStorage = GetSubraceStorageLocation(GetSubRace(oPC));
string WPTag = GetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_DEATH_LOCATION);
object oWP = GetWaypointByTag(WPTag);
return oWP;
}
// 3.0.6.4
void CreateSubraceDeathLocation(string subrace, string WaypointTag)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
SetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_DEATH_LOCATION, WaypointTag);
}
//3.0.6
void SSE_HorseAddHorseMenu(object oPC)
{ // PURPOSE: Add Horse Menu to the PC
object oSkin=SKIN_SupportGetSkin(oPC);
itemproperty iProp;
if (GetIsPC(oPC))
{ // valid parameter
iProp=ItemPropertyBonusFeat(40);
AddItemProperty(DURATION_TYPE_PERMANENT,iProp,oSkin);
} // valid parameter
} // HorseAddHorseMenu()
void NWNX_CreateSubraceDBTables()
{
if(ENABLE_NWNX_DATABASE)
{
string sTableName = SUBRACE_DATABASE;
// :: CREATE TABLE " + sTableName + "
// :: (
// :: player varchar(255) not null default '',
// :: tag varchar(255) not null,
// :: name varchar(255) not null,
// :: val text not null default '',
// :: expire int(8) not null default 0,
// :: PRIMARY KEY(player, tag, name)
// :: )
// :: TYPE=InnoDB;
string sSQL = "CREATE TABLE IF NOT EXISTS " + sTableName + "(player varchar(255) not null default '', tag varchar(255) not null, name varchar(255) not null, val text not null default '', expire int(8) not null default 0, PRIMARY KEY(player, tag, name))";
SQLExecDirect(sSQL);
}
}
void DeleteSubraceDBInt(string sCampaignName, string sVarName, object oPlayer)
{
if(ENABLE_NWNX_DATABASE)
{
if (!GetIsPC(oPlayer))
{
return;
}
string sPlayer = SQLEncodeSpecialChars(GetPCPlayerName(oPlayer));
string sCharName = SQLEncodeSpecialChars(GetStringLowerCase(GetName(oPlayer)));
sVarName = GetStringLowerCase(SQLEncodeSpecialChars(sVarName));
string sSQL = "SELECT val FROM " + sCampaignName + " WHERE player='" + sPlayer +
"' AND tag='" + sCharName + "' AND name='" + sVarName + "'";
SQLExecDirect(sSQL);
//Delete only if exists
if (SQLFetch() == SQL_SUCCESS)
{
sSQL = "DELETE FROM " + sCampaignName + " WHERE player='"+ sPlayer + "' AND tag='" + sCharName + "' AND name='" + sVarName + "'";
SQLExecDirect(sSQL);
}
}
else
{
//Delete only if exists
if(GetCampaignInt(sCampaignName, sVarName, oPlayer) )
{
DeleteCampaignVariable(sCampaignName, sVarName, oPlayer);
}
}
}
void SetSubraceDBInt(string sCampaignName, string sVarName, int nInt, object oPlayer=OBJECT_INVALID)
{
if(ENABLE_NWNX_DATABASE)
{
if (!GetIsPC(oPlayer))
{
return;
}
string sPlayer = SQLEncodeSpecialChars(GetPCPlayerName(oPlayer));
string sCharName = SQLEncodeSpecialChars(GetStringLowerCase(GetName(oPlayer)));
string sVal = IntToString(nInt);
sVarName = GetStringLowerCase(SQLEncodeSpecialChars(sVarName));
string sSQL = "SELECT val FROM " + sCampaignName + " WHERE player='" + sPlayer +
"' AND tag='" + sCharName + "' AND name='" + sVarName + "'";
SQLExecDirect(sSQL);
if (SQLFetch() == SQL_SUCCESS)
{
sSQL = "UPDATE " + sCampaignName + " SET val='" + sVal + "' WHERE player='"+ sPlayer + "' AND tag='" + sCharName + "' AND name='" + sVarName + "'";
SQLExecDirect(sSQL);
}
else
{
sSQL = "INSERT INTO " + sCampaignName + "(player,tag,name,val) VALUES ('" + sPlayer + "','" + sCharName + "','" + sVarName + "','" + sVal + "')";
SQLExecDirect(sSQL);
}
}
else
{
SetCampaignInt(sCampaignName, sVarName, nInt, oPlayer);
}
}
int GetSubraceDBInt(string sCampaignName, string sVarName, object oPlayer=OBJECT_INVALID)
{
int iInt;
if(ENABLE_NWNX_DATABASE)
{
if (!GetIsPC(oPlayer))
{
return 0;
}
string sPlayer = SQLEncodeSpecialChars(GetPCPlayerName(oPlayer));
string sCharName = SQLEncodeSpecialChars(GetStringLowerCase(GetName(oPlayer)));
sVarName = GetStringLowerCase(SQLEncodeSpecialChars(sVarName));
string sSQL = "SELECT val FROM " + sCampaignName + " WHERE player='" + sPlayer + "' AND tag='" + sCharName + "' AND name='" + sVarName + "'";
SQLExecDirect(sSQL);
if (SQLFirstRow() == SQL_SUCCESS)
{
return StringToInt(SQLGetData(1));
}
else
{
return 0;
}
}
else
{
iInt = GetCampaignInt(sCampaignName, sVarName, oPlayer);
}
return iInt;
}
void CreateSubrace(int Race, string subrace, string HideResRef = "", string UniqueItemResRef = "", int IsLightSensitive = FALSE, int DamageTakenWhileInLight = 0, int IsUndergroundSensitive = FALSE, int DamageTakenWhileInUnderground = 0, int ECL = 0, int IsUndead = FALSE, int PrestigiousSubrace = FALSE)
{
struct Subrace shaSubrace;
shaSubrace.BaseRace = Race;
shaSubrace.Name = subrace;
shaSubrace.SkinResRef = HideResRef;
shaSubrace.UniqueItemResRef = UniqueItemResRef;
shaSubrace.IsLightSensitive = IsLightSensitive;
shaSubrace.DamageTakenWhileInLight = DamageTakenWhileInLight;
shaSubrace.IsUndergroundSensitive = IsUndergroundSensitive;
shaSubrace.DamageTakenWhileInUnderground = DamageTakenWhileInUnderground;
shaSubrace.ECL = ECL;
shaSubrace.IsUndead = IsUndead;
shaSubrace.PrestigiousSubrace = PrestigiousSubrace;
SaveSubraceOnModule(shaSubrace);
}
//3.0.6.7
void CreateSubraceAlignmentRestriction(string subrace, int CanBeAlignment_Good = TRUE , int CanBeAlignment_Neutral1 = TRUE, int CanBeAlignment_Evil = TRUE, int CanBeAlignment_Lawful = TRUE, int CanBeAlignment_Neutral2 = TRUE, int CanBeAlignment_Chaotic = TRUE)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
int restri = FLAG1 | (CanBeAlignment_Good?FLAG2:0) | (CanBeAlignment_Neutral1?FLAG3:0) | (CanBeAlignment_Evil?FLAG4:0);
restri |= (CanBeAlignment_Lawful?FLAG5:0) | (CanBeAlignment_Neutral2?FLAG6:0) | (CanBeAlignment_Chaotic?FLAG7:0);
SetSSEInt(SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, restri);
}
//3.0.6.7
void CreateSubraceClassRestriction(string subrace, int CanBe_Barbarian = TRUE, int CanBe_Bard = TRUE, int CanBe_Cleric = TRUE, int CanBe_Druid = TRUE, int CanBe_Fighter = TRUE, int CanBe_Monk = TRUE, int CanBe_Paladin = TRUE, int CanBe_Ranger = TRUE, int CanBe_Rogue = TRUE, int CanBe_Sorcerer = TRUE, int CanBe_Wizard = TRUE)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
int restri = FLAG1 | (CanBe_Barbarian?FLAG2:0) | (CanBe_Bard?FLAG3:0) | (CanBe_Cleric?FLAG4:0);
restri |= (CanBe_Druid?FLAG5:0) | (CanBe_Fighter?FLAG6:0) | (CanBe_Monk?FLAG7:0);
restri |= (CanBe_Paladin?FLAG8:0) | (CanBe_Ranger?FLAG9:0) | (CanBe_Rogue?FLAG10:0);
restri |= (CanBe_Sorcerer?FLAG11:0) | (CanBe_Wizard?FLAG12:0);
SetSSEInt(SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, restri);
}
//3.0.6.7
void CreateSubraceGenderRestriction(string subrace, int CanBeMale = TRUE, int CanBeFemale = TRUE)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
int GenderFlag = (CanBeMale?0:FLAG2) | (CanBeFemale?0:FLAG1);
SetSSEInt(SubraceStorage + "_" + SUBRACE_GENDER_RES, GenderFlag);
}
void CreateSubraceSpellResistance(string subrace, int SpellResistanceBase, int SpellResistanceMax)
{
struct SubraceSpellResistance shaSubraceSpellRes;
shaSubraceSpellRes.subrace = subrace;
shaSubraceSpellRes.SpellResistanceBase = SpellResistanceBase;
shaSubraceSpellRes.SpellResistanceMax = SpellResistanceMax;
SaveSubraceSpellResistanceOnModule(shaSubraceSpellRes);
}
void CreateSubraceAppearance(string subrace, int AppearanceChangeTime, int MaleAppearance, int FemaleAppearance, int Level = 1)
{
struct SubraceDifferentAppearance shaSubraceApp;
if(AppearanceChangeTime == TIME_SPECIAL_APPEARANCE_SUBRACE)
{
AppearanceChangeTime = TIME_NONE;
}
shaSubraceApp.subrace = subrace;
shaSubraceApp.ChangeAppearanceTime = AppearanceChangeTime;
shaSubraceApp.MaleAppearance = MaleAppearance;
shaSubraceApp.FemaleAppearance = FemaleAppearance;
shaSubraceApp.Level = Level;
SaveSubraceAppearanceChangeOnModule(shaSubraceApp);
}
void AddAdditionalBaseRaceToSubrace(string subrace, int AdditionalBaseRace)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
int Flag = NOFLAGS;
switch(AdditionalBaseRace)
{
case RACIAL_TYPE_DWARF: Flag = FLAG1; break;
case RACIAL_TYPE_ELF: Flag = FLAG2; break;
case RACIAL_TYPE_GNOME: Flag = FLAG3; break;
case RACIAL_TYPE_HALFELF: Flag = FLAG4; break;
case RACIAL_TYPE_HALFLING: Flag = FLAG5; break;
case RACIAL_TYPE_HALFORC: Flag = FLAG6; break;
case RACIAL_TYPE_HUMAN: Flag = FLAG7; break;
case RACIAL_TYPE_ALL: Flag = ALLFLAGS; break;
default: Flag = NOFLAGS; break;
}
SetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_RACE, Flag, SUBRACE_BASE_RACE_FLAGS);
}
int GetIsSSEDisabledInArea(object Area=OBJECT_SELF)
{
if(!GetIsObjectValid(Area)) return FALSE;
return GetLocalInt(Area, "DISABLE_SUBRACE_ENGINE");
}
int GetIsSSEDisabled()
{
return GetSSEInt("SHUTDOWN_SSE");
}
int GetSSEStatus(object Area=OBJECT_INVALID)
{
int Value = SSE_STATUS_OPERATIONAL;
int StatusArea = GetIsSSEDisabledInArea(Area)?SSE_STATUS_DISABLED_IN_AREA:SSE_STATUS_OPERATIONAL;
int ServerSetting = GetIsSSEDisabled()?SSE_STATUS_DISABLED_IN_AREA:SSE_STATUS_OPERATIONAL;
Value = StatusArea | ServerSetting;
return Value;
}
void SetupSubraceAlias(string subrace, string Alias)
{
//Check if sub-race already exists.
if(GetSubraceID(Alias))
{
string Log="*Subrace Engine: Sub-race alias: ";
string trueName=GetSubraceNameByAlias(Alias);
Log+="ERROR\nAttempting to create sub-race alias [" + Alias + "] failed: Similar named sub-race ["+trueName+"] already exists";
WriteTimestampedLogEntry(Log);
return;
}
int ID = GetSubraceID(subrace);
if(!ID)
{
string Log="*Subrace Engine: Sub-race alias: ";
Log+="ERROR\nAttempting to create sub-race alias [" + Alias + "] for ["+subrace+"] failed: No sub-race with that name exists.";
WriteTimestampedLogEntry(Log);
return;
}
SetSubraceID(Alias, ID);
if(SSE_TREAT_ALIAS_AS_SUBRACE & 2)
{
string SubraceStorage = GetSubraceStorageLocationByID(ID);
int Num = GetSSEInt(SubraceStorage + "_ALIAS");
Num++;
SetLocalString(oStorer, SubraceStorage + "_ALIAS_" + IntToString(Num), Alias);
SetSSEInt(SubraceStorage + "_ALIAS", Num);
}
}
void AddSubraceEffect(string subrace, int EffectID, int Value1, int Value2, int nDurationType, float fDuration, int TimeOfDay)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
int Count = GetSSEInt(SubraceStorage + "_" + SUBRACE_EFFECT_COUNT);
Count++;
SetSSEInt(SubraceStorage + "_" + SUBRACE_EFFECT_COUNT, Count);
SubraceStorage = SubraceStorage + IntToString(Count);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_EFFECT, EffectID, SUBRACE_EFFECT_FLAGSET);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_EFFECT, Value1, SUBRACE_EFFECT_VALUE1_FLAGSET);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_EFFECT, Value2, SUBRACE_EFFECT_VALUE2_FLAGSET);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_EFFECT, TimeOfDay, SUBRACE_EFFECT_TIME_FLAGSET);
SetSSEInt(SubraceStorage + "_" + SUBRACE_EFFECT_DURATION_TYPE, nDurationType);
SetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_EFFECT_DURATION, fDuration);
}
void AddSubraceFavoredClass(string subrace, int MaleFavoredClass, int FamaleFavoredClass)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_FAVORED_CLASS, MaleFavoredClass + 1, SUBRACE_FAVORED_CLASS_MALE_FLAG);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_FAVORED_CLASS, FamaleFavoredClass + 1, SUBRACE_FAVORED_CLASS_FEMALE_FLAG);
}
void CreateSubraceSpecialRestriction(string subrace, int Type, string VarName, int Existance=TRUE, string Database="")
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
int Count = GetSSEInt(SubraceStorage + "_" + SUBRACE_SPECIAL_RESTRICTION);
Count++;
SetSSEInt(SubraceStorage + "_" + SUBRACE_SPECIAL_RESTRICTION, Count);
SubraceStorage = SubraceStorage +"_"+SUBRACE_SPECIAL_RESTRICTION+IntToString(Count);
SetSSEInt(SubraceStorage, Type | Existance);
SetLocalString(oStorer, SubraceStorage + SUBRACE_SPECIAL_RESTRICTION_VARNAME, VarName);
if(Database!="" && Database!=SUBRACE_DATABASE)
SetLocalString(oStorer, SubraceStorage + SUBRACE_SPECIAL_RESTRICTION_DATABASE, Database);
}
//3.0.6.7
void CreateSubracePrestigiousClassRestriction(string subrace, int MinimumLevels = 1, int CanBe_ArcaneArcher = TRUE, int CanBe_Assasin = TRUE, int CanBe_Blackguard = TRUE, int CanBe_ChampionOfTorm = TRUE, int CanBe_RedDragonDisciple = TRUE, int CanBe_DwarvenDefender = TRUE, int CanBe_HarperScout = TRUE, int CanBe_PaleMaster = TRUE, int CanBe_ShadowDancer = TRUE, int CanBe_Shifter = TRUE, int CanBe_WeaponMaster = TRUE, int CanBe_PurpleDragonKnight = TRUE)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
int restri = FLAG1 | (CanBe_ArcaneArcher?FLAG2:0) | (CanBe_Assasin?FLAG3:0) | (CanBe_Blackguard?FLAG4:0);
restri |= (CanBe_ChampionOfTorm?FLAG5:0) | (CanBe_RedDragonDisciple?FLAG6:0) | (CanBe_DwarvenDefender?FLAG7:0);
restri |= (CanBe_PaleMaster?FLAG8:0) | (CanBe_ShadowDancer?FLAG9:0) | (CanBe_Shifter?FLAG10:0);
restri |= (CanBe_WeaponMaster?FLAG11:0) | (CanBe_HarperScout?FLAG12:0) | (CanBe_PurpleDragonKnight?FLAG13:0);
SetSSEInt(SubraceStorage + "_" + SUBRACE_PRESTIGIOUS_CLASS_RESTRICTION, restri);
}
void CreateTemporaryStatModifier(string subrace, struct SubraceStats Stats, int TimeToApply, int InInteriorArea = TRUE, int InExteriorArea = TRUE, int InNaturalArea = TRUE, int InArtifacialArea = TRUE, int InUndergroundArea = TRUE, int InAbovegroundArea = TRUE)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
int iTime = TimeToApply | GetSSEInt(SubraceStorage + "_" + SUBRACE_STAT_MODIFIERS);
SetSSEInt(SubraceStorage + "_" + SUBRACE_STAT_MODIFIERS, iTime);
int ModType = Stats.ModType;
float StrengthModifier = Stats.StrengthModifier;
float DexterityModifier = Stats.DexterityModifier;
float ConstitutionModifier = Stats.ConstitutionModifier;
float IntelligenceModifier = Stats.IntelligenceModifier;
float WisdomModifier = Stats.WisdomModifier;
float CharismaModifier = Stats.CharismaModifier;
float ACModifier = Stats.ACModifier;
float ABModifier = Stats.ABModifier;
SubraceStorage = SubraceStorage + IntToString(TimeToApply);
SetSSEInt(SubraceStorage + "_" + SUBRACE_STAT_MODIFIER_TYPE, ModType);
//Flags
SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_STAT_MODIFIERS, FLAG4, InInteriorArea);
SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_STAT_MODIFIERS, FLAG5, InExteriorArea);
SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_STAT_MODIFIERS, FLAG6, InArtifacialArea);
SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_STAT_MODIFIERS, FLAG7, InNaturalArea);
SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_STAT_MODIFIERS, FLAG8, InAbovegroundArea);
SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_STAT_MODIFIERS, FLAG9, InUndergroundArea);
SetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_STAT_STR_MODIFIER, StrengthModifier);
SetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_STAT_DEX_MODIFIER, DexterityModifier);
SetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_STAT_CON_MODIFIER, ConstitutionModifier);
SetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_STAT_WIS_MODIFIER, WisdomModifier);
SetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_STAT_INT_MODIFIER, IntelligenceModifier);
SetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_STAT_CHA_MODIFIER, CharismaModifier);
SetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_STAT_AB_MODIFIER, ABModifier);
SetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_STAT_AC_MODIFIER, ACModifier);
SetSSEInt(SubraceStorage + "_" + SUBRACE_HAS_DAY_NIGHT_EFFECTS, TRUE);
}
//For StatModiferType use only SUBRACE_STAT_MODIFIER_TYPE_PERCENTAGE or SUBRACE_STAT_MODIFIER_TYPE_POINTS
struct SubraceStats CreateCustomStats(int StatModifierType, float StrengthModifier, float DexterityModifier, float ConstitutionModifier, float IntelligenceModifier, float WisdomModifier, float CharismaModifier, float ACModifier, float ABModifier)
{
struct SubraceStats Stats;
Stats.ModType = StatModifierType;
Stats.StrengthModifier = StrengthModifier;
Stats.DexterityModifier = DexterityModifier;
Stats.ConstitutionModifier = ConstitutionModifier;
Stats.IntelligenceModifier = IntelligenceModifier;
Stats.WisdomModifier = WisdomModifier;
Stats.CharismaModifier = CharismaModifier;
Stats.ACModifier = ACModifier;
Stats.ABModifier = ABModifier;
return Stats;
}
void SubraceRestrictUseOfItems(string subrace, int ItemType, int TimeOfDay = TIME_BOTH, int Allow = ITEM_TYPE_REQ_DO_NOT_ALLOW)
{
string SubraceStorage = GetSubraceStorageLocation(subrace) + "_" + SUBRACE_ITEM_RESTRICTION + "_";
int Set = ItemType;
if(! (Allow & ITEM_TYPE_REQ_DO_NOT_ALLOW) )
{
Set = (~Set);
}
if(Allow & ITEM_TYPE_REQ_ALL)
{
Set |= ITEM_TYPE_REQ_ALL;
}
else
{
Set &= (~ITEM_TYPE_REQ_ALL);
}
switch(TimeOfDay)
{
case TIME_NONE:
//We no use TIME_NONE here, mon. Da i-da-ot mean subrace-form me thinks!
TimeOfDay = TIME_SPECIAL_APPEARANCE_SUBRACE; //No break mon!
case TIME_NIGHT:
case TIME_DAY:
case TIME_SPECIAL_APPEARANCE_SUBRACE:
case TIME_SPECIAL_APPEARANCE_NORMAL:
SetLocalInt( oStorer, SubraceStorage + IntToString(TimeOfDay), Set);
break;
case TIME_BOTH:
SetLocalInt( oStorer, SubraceStorage + IntToString(TIME_NIGHT), Set);
SetLocalInt( oStorer, SubraceStorage + IntToString(TIME_DAY), Set);
break;
}
if(GetSSEInt(SubraceStorage + IntToString(TIME_SPECIAL_APPEARANCE_NORMAL))
&& GetSSEInt(SubraceStorage + IntToString(TIME_SPECIAL_APPEARANCE_SUBRACE)) )
{
//Both Appearance forms have restrictions, No time based restrictions.
if(GetSSEInt(SubraceStorage + IntToString(TIME_DAY)))
DeleteSSEInt( SubraceStorage + IntToString(TIME_DAY));
if(GetSSEInt(SubraceStorage + IntToString(TIME_NIGHT)))
DeleteSSEInt( SubraceStorage + IntToString(TIME_NIGHT));
}
}
void SetupSubraceSwitch(string subrace, string switchSubraceNames, int Level, int MustMeetRequirements = TRUE)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
SetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_SWITCH_NAME + IntToString(Level), switchSubraceNames);
if(MustMeetRequirements)
{
SetSSEInt( SubraceStorage + "_" + SUBRACE_SWITCH_MUST_MEET_REQUIREMENTS + IntToString(Level), TRUE);
}
}
//:: Internal Functions
void SaveSubraceOnModule(struct Subrace shaSubrace)
{
string subrace = (SSE_AUTO_FORMAT_SUBRACE_NAMES?CapitalizeString(shaSubrace.Name):shaSubrace.Name);
//Check if sub-race already exists.
if(GetSubraceID(subrace))
{
string Log="*Subrace Engine: Sub-race creation: ";
string trueName=GetSubraceNameByAlias(subrace);
if(GetStringLowerCase(trueName) == GetStringLowerCase(subrace))
{
//Sub-race already exists, die...
Log+="ERROR\nAttempting to create sub-race [" + shaSubrace.Name + "] failed: Sub-race already exists";
WriteTimestampedLogEntry(Log);
return;
}
Log+="WARNING\nSub-race Alias [" + shaSubrace.Name + "] for the sub-race ["+trueName+"] was overriden, when Sub-race ["+subrace+"] was created.";
}
//Save the count, and the name of the subrace.
int iCount = GetSSEInt( MODULE_SUBRACE_COUNT);
iCount++;
SetSubraceID(subrace, iCount);
SetSSEInt( MODULE_SUBRACE_COUNT, iCount);
SetLocalString(oStorer, MODULE_SUBRACE_NUMBER + IntToString(iCount), subrace);
string SubraceStorage = GetSubraceStorageLocation(subrace);
int Flag = NOFLAGS;
switch(shaSubrace.BaseRace)
{
case RACIAL_TYPE_DWARF: Flag = FLAG1; break;
case RACIAL_TYPE_ELF: Flag = FLAG2; break;
case RACIAL_TYPE_GNOME: Flag = FLAG3; break;
case RACIAL_TYPE_HALFELF: Flag = FLAG4; break;
case RACIAL_TYPE_HALFLING: Flag = FLAG5; break;
case RACIAL_TYPE_HALFORC: Flag = FLAG6; break;
case RACIAL_TYPE_HUMAN: Flag = FLAG7; break;
case RACIAL_TYPE_ALL: Flag = ALLFLAGS; break;
default: Flag = NOFLAGS; break;
}
SetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_RACE, Flag, SUBRACE_BASE_RACE_FLAGS);
if(shaSubrace.SkinResRef != "none" && shaSubrace.SkinResRef != "")
{
SetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_SKIN + "_1" + "_" + IntToString(TIME_BOTH), GetStringLowerCase( shaSubrace.SkinResRef ));
}
if(shaSubrace.UniqueItemResRef != "" && shaSubrace.UniqueItemResRef != "none")
{
int SubraceUniqueItemCount = 1;
SetSSEInt( SubraceStorage + "_" + SUBRACE_UNIQUEITEM_COUNT, SubraceUniqueItemCount);
SetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_UNIQUEITEM + "_1",GetStringLowerCase( shaSubrace.UniqueItemResRef ) + "_1");
}
SetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_LIGHT_SENSITIVE, SUBRACE_BASE_INFORMATION_FLAGS, shaSubrace.IsLightSensitive);
SetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_UNDERGROUND_SENSITIVE, SUBRACE_BASE_INFORMATION_FLAGS, shaSubrace.IsUndergroundSensitive);
SetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_UNDEAD, SUBRACE_BASE_INFORMATION_FLAGS, shaSubrace.IsUndead);
SetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_PRESTIGIOUS_SUBRACE, SUBRACE_BASE_INFORMATION_FLAGS, shaSubrace.PrestigiousSubrace);
if(shaSubrace.DamageTakenWhileInLight)
{
SetSSEInt( SubraceStorage + "_" + DAMAGE_AMOUNT_IN_LIGHT, shaSubrace.DamageTakenWhileInLight);
}
if(shaSubrace.DamageTakenWhileInUnderground)
{
SetSSEInt( SubraceStorage + "_" + DAMAGE_AMOUNT_IN_UNDERGROUND, shaSubrace.DamageTakenWhileInUnderground);
}
if(shaSubrace.ECL)
{
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, shaSubrace.ECL, SUBRACE_BASE_INFORMATION_ECL);
}
if(shaSubrace.DamageTakenWhileInUnderground || shaSubrace.DamageTakenWhileInLight || shaSubrace.IsLightSensitive || shaSubrace.IsUndergroundSensitive)
{
SetSSEInt( SubraceStorage + "_" + SUBRACE_HAS_DAY_NIGHT_EFFECTS, TRUE);
}
}
//3.0.6.7
void SaveSubraceAlignmentRestrictionOnModule(struct SubraceAlignmentRestriction shaSubraceAlignRes)
{
string SubraceStorage = GetSubraceStorageLocation(shaSubraceAlignRes.subrace);
int restri = FLAG1 | (shaSubraceAlignRes.CanBeAlignment_Good?FLAG2:0) | (shaSubraceAlignRes.CanBeAlignment_Neutral1?FLAG3:0) | (shaSubraceAlignRes.CanBeAlignment_Evil?FLAG4:0);
restri |= (shaSubraceAlignRes.CanBeAlignment_Lawful?FLAG5:0) | (shaSubraceAlignRes.CanBeAlignment_Neutral2?FLAG6:0) | (shaSubraceAlignRes.CanBeAlignment_Chaotic?FLAG7:0);
SetSSEInt(SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, restri);
/*
string SubraceStorage = GetSubraceStorageLocation(shaSubraceAlignRes.subrace);
SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG1, TRUE);
SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG2, shaSubraceAlignRes.CanBeAlignment_Good);
SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG3, shaSubraceAlignRes.CanBeAlignment_Neutral1);
SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG4, shaSubraceAlignRes.CanBeAlignment_Evil);
SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG5, shaSubraceAlignRes.CanBeAlignment_Lawful);
SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG6, shaSubraceAlignRes.CanBeAlignment_Neutral2);
SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG7, shaSubraceAlignRes.CanBeAlignment_Chaotic);
*/
}
//3.0.6.7
void SaveSubraceClassRestrictionOnModule(struct SubraceClassRestriction shaSubraceClassRes)
{
string SubraceStorage = GetSubraceStorageLocation(shaSubraceClassRes.subrace);
int restri = FLAG1 | (shaSubraceClassRes.CanBe_Barbarian?FLAG2:0) | (shaSubraceClassRes.CanBe_Bard?FLAG3:0) | (shaSubraceClassRes.CanBe_Cleric?FLAG4:0);
restri |= (shaSubraceClassRes.CanBe_Druid?FLAG5:0) | (shaSubraceClassRes.CanBe_Fighter?FLAG6:0) | (shaSubraceClassRes.CanBe_Monk?FLAG7:0);
restri |= (shaSubraceClassRes.CanBe_Paladin?FLAG8:0) | (shaSubraceClassRes.CanBe_Ranger?FLAG9:0) | (shaSubraceClassRes.CanBe_Rogue?FLAG10:0);
restri |= (shaSubraceClassRes.CanBe_Sorcerer?FLAG11:0) | (shaSubraceClassRes.CanBe_Wizard?FLAG12:0);
SetSSEInt(SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, restri);
}
void SaveSubraceSpellResistanceOnModule(struct SubraceSpellResistance shaSubraceSpellRes)
{
string SubraceStorage = GetSubraceStorageLocation(shaSubraceSpellRes.subrace);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_SPELL_RESISTANCE, shaSubraceSpellRes.SpellResistanceBase,SUBRACE_SPELL_RESISTANCE_BASE_FLAGS);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_SPELL_RESISTANCE, shaSubraceSpellRes.SpellResistanceMax, SUBRACE_SPELL_RESISTANCE_MAX_FLAGS);
}
void SaveSubraceAppearanceChangeOnModule(struct SubraceDifferentAppearance shaSubraceApp)
{
string SubraceStorage = GetSubraceStorageLocation(shaSubraceApp.subrace);
SubraceStorage = SubraceStorage + "_" + IntToString(shaSubraceApp.Level);
SetLocalGroupFlag(oStorer, SubraceStorage + "_" + APPEARANCE_CHANGE, shaSubraceApp.ChangeAppearanceTime, TIME_FLAGS);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + APPEARANCE_TO_CHANGE, shaSubraceApp.MaleAppearance, APPEARANCE_CHANGE_MALE_FLAG);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + APPEARANCE_TO_CHANGE, shaSubraceApp.FemaleAppearance, APPEARANCE_CHANGE_FEMALE_FLAG);
}
void AddAdditionalSkinsToSubrace(string subrace, string SkinResRef, int EquipLevel, int iTime = TIME_BOTH)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
SetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_SKIN + "_" + IntToString(EquipLevel) + "_" + IntToString(iTime), GetStringLowerCase( SkinResRef ) );
}
void AddClawsToSubrace(string subrace, string RightClawResRef, string LeftClawResRef , int EquipLevel, int iTime = TIME_BOTH)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
if(RightClawResRef != "")
{
SetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_RIGHT_CLAW + "_" + IntToString(EquipLevel) + "_" + IntToString(iTime), RightClawResRef);
}
if(LeftClawResRef != "")
{
SetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_LEFT_CLAW + "_" + IntToString(EquipLevel) + "_" + IntToString(iTime), LeftClawResRef);
}
}
void AddSubraceItem(string subrace, string ItemResRef, int Level = 1)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
int SubraceUniqueItemCount = GetSSEInt( SubraceStorage + "_" + SUBRACE_UNIQUEITEM_COUNT);
SubraceUniqueItemCount++;
SetSSEInt( SubraceStorage + "_" + SUBRACE_UNIQUEITEM_COUNT, SubraceUniqueItemCount);
SetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_UNIQUEITEM + "_" + IntToString(SubraceUniqueItemCount), GetStringLowerCase( ItemResRef ) + "_" + IntToString(Level));
}
//LETO STUFF
struct SubraceBaseStatsModifier CustomBaseStatsModifiers(int StrengthModifier, int DexterityModifier, int ConstitutionModifier, int IntelligenceModifier, int WisdomModifier, int CharismaModifier, int MovementSpeedModifier)
{
struct SubraceBaseStatsModifier Stats;
Stats.StrengthModifier = StrengthModifier;
Stats.DexterityModifier = DexterityModifier;
Stats.ConstitutionModifier = ConstitutionModifier;
Stats.IntelligenceModifier = IntelligenceModifier;
Stats.WisdomModifier = WisdomModifier;
Stats.CharismaModifier = CharismaModifier;
Stats.SpdModifier = MovementSpeedModifier;
return Stats;
}
void CreateBaseStatModifier(string subrace, struct SubraceBaseStatsModifier Stats, int Level = 1, int Set = FALSE)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
int StrengthModifier = Stats.StrengthModifier;
int DexterityModifier = Stats.DexterityModifier;
int ConstitutionModifier = Stats.ConstitutionModifier;
int IntelligenceModifier = Stats.IntelligenceModifier;
int WisdomModifier = Stats.WisdomModifier;
int CharismaModifier = Stats.CharismaModifier;
int SpdModifier = Stats.SpdModifier;
SubraceStorage = SubraceStorage + "_" + IntToString(Level);
SetSSEInt( SubraceStorage + "_" + SUBRACE_HAS_BASE_STAT_MODIFIERS, TRUE);
if(Set)
{
SetSSEInt( SubraceStorage + "_" + SUBRACE_BASE_STAT_MODIFIERS_REPLACE, Set);
}
if(StrengthModifier)
{
SetSSEInt( SubraceStorage + "_" + SUBRACE_BASE_STAT_STR_MODIFIER, StrengthModifier);
}
if(DexterityModifier)
{
SetSSEInt( SubraceStorage + "_" + SUBRACE_BASE_STAT_DEX_MODIFIER, DexterityModifier);
}
if(ConstitutionModifier)
{
SetSSEInt( SubraceStorage + "_" + SUBRACE_BASE_STAT_CON_MODIFIER, ConstitutionModifier);
}
if(WisdomModifier)
{
SetSSEInt( SubraceStorage + "_" + SUBRACE_BASE_STAT_WIS_MODIFIER, WisdomModifier);
}
if(IntelligenceModifier)
{
SetSSEInt( SubraceStorage + "_" + SUBRACE_BASE_STAT_INT_MODIFIER, IntelligenceModifier);
}
if(CharismaModifier)
{
SetSSEInt( SubraceStorage + "_" + SUBRACE_BASE_STAT_CHA_MODIFIER, CharismaModifier);
}
if(SpdModifier)
{
SetSSEInt( SubraceStorage + "_" + SUBRACE_BASE_STAT_SPD_MODIFIER, SpdModifier);
}
}
void ModifySubraceFaction(string subrace, string FactionCreatureTag, int Reputation = SUBRACE_FACTION_REPUTATION_HOSTILE)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
int Count = GetSSEInt( SubraceStorage + "_" + SUBRACE_FACTION_COUNT);
Count++;
SetSSEInt( SubraceStorage + "_" + SUBRACE_FACTION_COUNT, Count);
SetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_FACTION_CREATURE + "_" + IntToString(Count), FactionCreatureTag);
SetSSEInt( SubraceStorage + "_" + SUBRACE_FACTION_REPUTATION + "_" + IntToString(Count), Reputation);
}
void CreateSubraceStartLocation(string subrace, string WaypointTag)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
SetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_START_LOCATION, WaypointTag);
}
void ModifySubraceAppearanceAttachment(string subrace, int Male_Wings = 0, int Female_Wings = 0, int Male_Tail = 0, int Female_Tail = 0, int Level = 1)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
SubraceStorage = SubraceStorage + "_" + IntToString(Level);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_ATTACHMENT_FLAGS, Male_Wings, SUBRACE_ATTACHMENT_FLAGS_WINGS_MALE);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_ATTACHMENT_FLAGS, Female_Wings, SUBRACE_ATTACHMENT_FLAGS_WINGS_FEMALE);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_ATTACHMENT_FLAGS, Male_Tail, SUBRACE_ATTACHMENT_FLAGS_TAIL_MALE);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_ATTACHMENT_FLAGS, Female_Tail, SUBRACE_ATTACHMENT_FLAGS_TAIL_FEMALE);
}
void ModifySubraceFeat(string subrace, int FeatID, int Level = 1, int Remove = FALSE)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
SubraceStorage = SubraceStorage + "_" + IntToString(Level);
int FeatCount = GetSSEInt( SubraceStorage + "_" + SUBRACE_BONUS_FEAT_COUNT);
FeatCount++;
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + IntToString(FeatCount) + "_" + SUBRACE_BONUS_FEAT_FLAGS, FeatID, SUBRACE_BONUS_FEAT_FLAG);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + IntToString(FeatCount) + "_" + SUBRACE_BONUS_FEAT_FLAGS, Remove, SUBRACE_BONUS_FEAT_REMOVE_FLAG);
SetSSEInt( SubraceStorage + "_" + SUBRACE_BONUS_FEAT_COUNT, FeatCount);
}
void ChangePortrait(string subrace, string MalePortrait, string FemalePortrait, int Level = 1)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
SetLocalString(oStorer, SubraceStorage + "_" + IntToString(Level)+ "_" + SUBRACE_PORTRAIT_MALE, MalePortrait);
SetLocalString(oStorer, SubraceStorage + "_" + IntToString(Level)+ "_" + SUBRACE_PORTRAIT_FEMALE , FemalePortrait);
}
void ChangeSoundSet(string subrace, int MaleSoundSet, int FemaleSoundSet, int Level = 1)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + IntToString(Level)+ "_" + SUBRACE_SOUNDSET_FLAGS, MaleSoundSet, SUBRACE_SOUNDSET_MALE_FLAG);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + IntToString(Level)+ "_" + SUBRACE_SOUNDSET_FLAGS, FemaleSoundSet, SUBRACE_SOUNDSET_FEMALE_FLAG);
}
void ModifySubraceSkill(string subrace, int SkillID, int iModifier, int Level = 1, int Set = FALSE)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
SubraceStorage = SubraceStorage + "_" + IntToString(Level);
int SkillCount = GetSSEInt( SubraceStorage + "_" + SUBRACE_BONUS_SKILL_COUNT);
SkillCount++;
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + IntToString(SkillCount) + "_" + SUBRACE_BONUS_SKILL_FLAGS, SkillID, SUBRACE_BONUS_SKILL_FLAG);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + IntToString(SkillCount) + "_" + SUBRACE_BONUS_SKILL_FLAGS, Set, SUBRACE_BONUS_SKILL_REMOVE_FLAG);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + IntToString(SkillCount) + "_" + SUBRACE_BONUS_SKILL_FLAGS, iModifier, SUBRACE_BONUS_SKILL_MODIFIER_FLAG);
SetSSEInt( SubraceStorage + "_" + SUBRACE_BONUS_SKILL_COUNT, SkillCount);
}
void ModifySubraceAppearanceColors(string subrace, int Male_Hair = -1, int Female_Hair = -1, int Male_Skin = -1, int Female_Skin = -1, int Level = 1)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
SubraceStorage = SubraceStorage + "_" + IntToString(Level);
//3.0.6.6 negative value omissions fixed
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_COLORS_FLAGS, Male_Hair, SUBRACE_COLORS_FLAGS_HAIR_MALE);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_COLORS_FLAGS, Female_Hair, SUBRACE_COLORS_FLAGS_HAIR_FEMALE);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_COLORS_FLAGS, Male_Skin, SUBRACE_COLORS_FLAGS_SKIN_MALE);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_COLORS_FLAGS, Female_Skin, SUBRACE_COLORS_FLAGS_SKIN_FEMALE);
}
// 3.0.6.9
void ModifySubraceHead(string subrace, int Male_Head = -1, int Female_Head = -1, int Level = 1)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
SubraceStorage = SubraceStorage + "_" + IntToString(Level);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_HEAD_FLAGS, Male_Head, SUBRACE_HEAD_FLAGS_MALE);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_HEAD_FLAGS, Female_Head, SUBRACE_HEAD_FLAGS_FEMALE);
}
// 3.0.6.6
// 3.0.6.9.11 renamed
void SHA_ModifySubraceEyeColors(string subrace, int Male_Eyes = -1, int Female_Eyes = -1, int Level = 1)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
SubraceStorage = SubraceStorage + "_" + IntToString(Level);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_EYE_COLORS_FLAGS, Male_Eyes, SUBRACE_EYE_COLORS_FLAGS_MALE);
SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_EYE_COLORS_FLAGS, Female_Eyes, SUBRACE_EYE_COLORS_FLAGS_FEMALE);
}
void DelayBoot(object oPC)
{
if(GetLocalInt(oPC, "SUBRACE_NEEDS_TO_RELOG"))
{
BootPC(oPC);
}
}
void SetIsInDarkness(object oPC, int Flag)
{
int ID = GetPlayerSubraceID(oPC);
if(!ID) { return; }
string SubraceStorage = GetSubraceStorageLocationByID(ID);
int IsLightSens = GetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_LIGHT_SENSITIVE, SUBRACE_BASE_INFORMATION_FLAGS);
int DmgTakenL = GetSSEInt( SubraceStorage + "_" + DAMAGE_AMOUNT_IN_LIGHT);
if(IsLightSens || DmgTakenL)
{
SetLocalInt(oPC, SUBRACE_IN_SPELL_DARKNESS, Flag);
}
}
int Subrace_GetIsInDarkness(object oPC)
{
return GetLocalInt(oPC, SUBRACE_IN_SPELL_DARKNESS);
}
void ApplyLightSensitivity(object oPC)
{
if(SPELL_DARKNESS_STOPS_LIGHT_SENSITIVITY && Subrace_GetIsInDarkness(oPC))
{
return;
}
if(!GetLocalInt(oPC, "STRUCK_BLIND"))
{
if(APPLY_LIGHT_BLINDNESS)
{
if(FortitudeSave(oPC, LIGHT_SENSITIVE_SAVING_THROW_DC) == 0)
{
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectBlindness(), oPC, RoundsToSeconds(LIGHT_STRUCK_BLIND_FOR_ROUNDS));
}
SetLocalInt(oPC, "STRUCK_BLIND", TRUE);
DelayCommand(RoundsToSeconds(LIGHT_BLINDNESS_STRIKES_EVERY_ROUND), SetLocalInt(oPC, "STRUCK_BLIND", FALSE));
}
}
if(APPLY_AB_AND_SAVING_THROW_DECREASES_IN_LIGHT && !GetLocalInt(oPC, "STRUCK_LIGHT_DEC"))
{
effect ABDecrease = EffectAttackDecrease(LIGHT_AB_DECREASE, ATTACK_BONUS_ONHAND);
effect ABDecrease1 = EffectAttackDecrease(LIGHT_AB_DECREASE, ATTACK_BONUS_OFFHAND);
effect SaveDecrease = EffectSavingThrowDecrease(SAVING_THROW_ALL, LIGHT_SAVE_DECREASE, SAVING_THROW_TYPE_ALL);
effect Link = EffectLinkEffects(ABDecrease, ABDecrease1);
Link = SupernaturalEffect(EffectLinkEffects(SaveDecrease, Link));
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, Link, oPC, RoundsToSeconds(LIGHT_CAUSES_AB_AND_SAVES_DECREASE_FOR_ROUNDS + 1));
SetLocalInt(oPC, "STRUCK_LIGHT_DEC", TRUE);
DelayCommand(RoundsToSeconds(LIGHT_CAUSES_AB_AND_SAVES_DECREASE_FOR_ROUNDS), SetLocalInt(oPC, "STRUCK_LIGHT_DEC", FALSE));
}
}
int GetIsPCLightSensitive(object oPC)
{
string SubraceStorage = GetSubraceStorageLocationByID(GetPlayerSubraceID(oPC));
return GetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_LIGHT_SENSITIVE, SUBRACE_BASE_INFORMATION_FLAGS);
}
void ApplyUndergroundSensitivity(object oPC)
{
if(!GetLocalInt(oPC, "STRUCK_BLIND_UND"))
{
if(FortitudeSave(oPC, DARK_SENSITIVE_SAVING_THROW_DC) == 0)
{
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectBlindness(), oPC, DARK_STRUCK_BLIND_FOR_ROUNDS*6.0);
}
SetLocalInt(oPC, "STRUCK_BLIND_UND", TRUE);
DelayCommand(RoundsToSeconds(DARK_BLINDNESS_STRIKES_EVERY_ROUND), SetLocalInt(oPC, "STRUCK_BLIND_UND", FALSE));
}
}
void SubraceSpontaneouslyCombust(object oPC)
{
if(ReflexSave(oPC, SUBRACE_SPONTANEOUSLY_COMBUST_DC) )
{ return; }
effect FireDmg = EffectDamage(d8(), DAMAGE_TYPE_FIRE, DAMAGE_POWER_NORMAL);
effect VisEffect = EffectVisualEffect(VFX_IMP_FLAME_S);
effect iLink = EffectLinkEffects(FireDmg, VisEffect);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, iLink, oPC, 6.0);
}
void ApplyDamageWhileInLight(object oPC, int DmgTaken)
{
// Add 2 new vars for Vamp Light Damage: Dayon Kinslayer: 2/23/2006
// Added check for Enforcer wand or SpiteMe Invisibility
int iClassLvl;
int iMaxHP;
if(SPELL_DARKNESS_STOPS_LIGHT_SENSITIVITY && Subrace_GetIsInDarkness(oPC))
{
return;
}
if(!GetLocalInt(oPC, "SB_LGHT_DMGED"))
{
SetLocalInt(oPC, "SB_LGHT_DMGED", TRUE);
effect LightDamage;
effect eImmuneDecrease;
if(DmgTaken > 0)
{
// Changes made by Dayon Kinslayer: 2/23/2006
// Commented original code
//LightDamage = EffectDamage( DmgTaken, DAMAGE_TYPE_MAGICAL, DAMAGE_POWER_PLUS_TWENTY);
// Get Character Level
iClassLvl = GetHitDice( oPC );
// If Level 5 or below, you die (take max HP damage)
// If Level 6 or above, take 25% of max HP. You have 4 rounds, run.
if( iClassLvl < 6 ) {
iMaxHP = GetMaxHitPoints( oPC );
} else {
iMaxHP = GetMaxHitPoints( oPC );
float fQuarterHP = IntToFloat( iMaxHP )/4;
}
LightDamage = EffectDamage( iMaxHP, DAMAGE_TYPE_MAGICAL, DAMAGE_POWER_PLUS_TWENTY);
}
else if(DmgTaken < 0)
{
DmgTaken = abs(DmgTaken);
LightDamage = EffectRegenerate(DmgTaken, 1.0);
}
if(SUBRACE_SPONTANEOUS_COMBUSTION_WHILE_IN_LIGHT)
{
if(d100() <= SUBRACE_SPONTANEOUS_COMBUSTION_PERCENTAGE)
{
int i = 0;
//Combust visual effect.
effect eDur = EffectVisualEffect(498);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDur, oPC, RoundsToSeconds(LIGHT_DAMAGES_EVERY_ROUNDS));
while(i != LIGHT_DAMAGES_EVERY_ROUNDS)
{
DelayCommand(RoundsToSeconds(i), SubraceSpontaneouslyCombust(oPC));
i++;
}
}
}
// Reduce immunity from Magic damage by 100% temporarily.
// eImmuneDecrease = EffectDamageImmunityDecrease( DAMAGE_TYPE_MAGICAL, 50 );
// ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eImmuneDecrease, oPC, 1.0);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, LightDamage, oPC, 1.0);
DelayCommand(RoundsToSeconds(LIGHT_DAMAGES_EVERY_ROUNDS), SetLocalInt(oPC,"SB_LGHT_DMGED", FALSE));
}
}
int GetSubraceID(string subrace)
{
return GetSSEInt( SUBRACE_TAG + "_" + GetStringLowerCase(subrace));
}
void SetSubraceID(string subrace, int Value)
{
SetSSEInt( SUBRACE_TAG + "_" + GetStringLowerCase(subrace), Value);
}
string GetSubraceStorageLocationByID(int SubraceID)
{
return SUBRACE_TAG + "_ID_" + IntToHexString(SubraceID);
}
string GetSubraceStorageLocation(string subrace)
{
return GetSubraceStorageLocationByID(GetSubraceID(subrace));
}
void ApplyDamageWhileInDark(object oPC, int DmgTaken)
{
if(!GetLocalInt(oPC, "SB_DARK_DMGED"))
{
SetLocalInt(oPC, "SB_DARK_DMGED", TRUE);
effect DarkDamage;
if(DmgTaken > 0)
{
DarkDamage = EffectDamage(DmgTaken, DAMAGE_TYPE_NEGATIVE, DAMAGE_POWER_ENERGY);
}
else if(DmgTaken < 0)
{
DmgTaken = abs(DmgTaken);
DarkDamage = EffectRegenerate(DmgTaken, 1.0);
}
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, DarkDamage, oPC, 1.0);
DelayCommand(RoundsToSeconds(DARKNESS_DAMAGES_EVERY_ROUNDS), SetLocalInt(oPC,"SB_DARK_DMGED", FALSE));
}
}
string FlagNumberToErrorMSG(int iError)
{
string sReturn = "";
if(iError & SUBRACE_ERROR_UNRECOGNISED)
{
//Exploiting the fact that "unrecognised subrace" never gets any other "errors"
/*sReturn +=*/return "\n-" + SSE_GetStandardMessage(MESSAGE_SUBRACE_UNRECOGNISED);
}
if(iError & SUBRACE_ERROR_ALIGNMENT)
{
sReturn += "\n-" + SSE_GetStandardMessage(MESSAGE_SUBRACE_CRITERIA_ALIGNMENT_FAILED);
}
if(iError & SUBRACE_ERROR_RACE)
{
sReturn += "\n-" + SSE_GetStandardMessage(MESSAGE_SUBRACE_CRITERIA_BASE_RACE_FAILED);
}
if(iError & SUBRACE_ERROR_CLASS)
{
sReturn += "\n-" + SSE_GetStandardMessage(MESSAGE_SUBRACE_CRITERIA_CLASS_FAILED);
}
if(iError & SUBRACE_ERROR_PRESTIGE_FAILURE)
{
sReturn += "\n-" + SSE_GetStandardMessage(MESSAGE_FAILED_TO_MEET_PRESTIGIOUS_CLASS_RESTRICTION);
}
if(iError & SUBRACE_ERROR_PRESTIGE_NOT_MET)
{
sReturn += "\n-" + SSE_GetStandardMessage(MESSAGE_CANNOT_BE_PART_OF_PRESTIGIOUS_SUBRACE);
}
if(iError & SUBRACE_ERROR_GENDER)
{
sReturn += "\n-" + SSE_GetStandardMessage(MESSAGE_SUBRACE_GENDER_FAILED);
}
if(iError & SUBRACE_ERROR_SPECIAL_RESTRICTION)
{
sReturn += "\n-" + SSE_GetStandardMessage(MESSAGE_SUBRACE_CRITERIA_SPECIAL_RESTRICTION_FAILED);
}
return sReturn;
}
//3.0.6.7
int PrestigeClassToFlags(int Class)
{
int Flag = 0;
switch(Class)
{
case CLASS_TYPE_ARCANE_ARCHER:
Flag = FLAG2;
break;
case CLASS_TYPE_ASSASSIN:
Flag = FLAG3;
break;
case CLASS_TYPE_BLACKGUARD:
Flag = FLAG4;
break;
case CLASS_TYPE_DIVINE_CHAMPION:
Flag = FLAG5;
break;
case CLASS_TYPE_DRAGON_DISCIPLE:
Flag = FLAG6;
break;
case CLASS_TYPE_DWARVEN_DEFENDER:
Flag = FLAG7;
break;
case CLASS_TYPE_HARPER:
Flag = FLAG8;
break;
case CLASS_TYPE_PALE_MASTER:
Flag = FLAG9;
break;
case CLASS_TYPE_SHADOWDANCER:
Flag = FLAG10;
break;
case CLASS_TYPE_SHIFTER:
Flag = FLAG11;
break;
case CLASS_TYPE_WEAPON_MASTER:
Flag = FLAG12;
break;
case CLASS_TYPE_PURPLE_DRAGON_KNIGHT:
Flag = FLAG13;
break;
}
return Flag;
}
int RacialTypeToFlags(int Race)
{
int Flag = 0;
switch(Race)
{
case RACIAL_TYPE_DWARF:
Flag = FLAG1;
break;
case RACIAL_TYPE_ELF:
Flag = FLAG2;
break;
case RACIAL_TYPE_GNOME:
Flag = FLAG3;
break;
case RACIAL_TYPE_HALFELF:
Flag = FLAG4;
break;
case RACIAL_TYPE_HALFLING:
Flag = FLAG5;
break;
case RACIAL_TYPE_HALFORC:
Flag = FLAG6;
break;
case RACIAL_TYPE_HUMAN:
Flag = FLAG7;
break;
case RACIAL_TYPE_ALL:
Flag = FLAG8;
break;
}
return Flag;
}
int CheckIfPCMeetsBaseRaceCriteria(object oPC, string SubraceStorage)
{
int PCRace = GetRacialType(oPC);
int iResult = GetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_BASE_RACE, SUBRACE_BASE_RACE_FLAGS);
return (iResult)?(iResult & RacialTypeToFlags(PCRace)):TRUE;
}
int CheckIfPCMeetsSpecialCriteria(object oPC, string SubraceStorage)
{
SubraceStorage = SubraceStorage +"_"+SUBRACE_SPECIAL_RESTRICTION;
int Count = GetSSEInt( SubraceStorage);
string Test;
int i=1;
int Type, TestValue;
string Varname, Database;
int ReturnValue=TRUE;
for( ; (i<=Count) && ReturnValue ; i++)
{
Test=SubraceStorage+IntToString(i);
Type=GetSSEInt( Test);
Varname=GetLocalString(oStorer, Test + SUBRACE_SPECIAL_RESTRICTION_VARNAME);
Database=GetLocalString(oStorer, Test + SUBRACE_SPECIAL_RESTRICTION_DATABASE);
switch(Type&SUBRACE_SPECIAL_RESTRICTION_TYPE_ALL)
{
case SUBRACE_SPECIAL_RESTRICTION_TYPE_DATABASE:
if(Database=="") Database=SUBRACE_DATABASE;
TestValue=GetSubraceDBInt(Database, Varname, oPC);
break;
case SUBRACE_SPECIAL_RESTRICTION_TYPE_ITEM:
TestValue=GetIsObjectValid(GetItemPossessedBy(oPC, Varname));
break;
case SUBRACE_SPECIAL_RESTRICTION_TYPE_LOCAL_VAR:
{
object Temp;
if(Database!="")
{
Temp = GetItemPossessedBy(oPC, Database);
if(!GetIsObjectValid(Temp))
{
Temp=GetObjectByTag(Database);
if(!GetIsObjectValid(Temp))
{
Temp=oPC;
}
}
}
else Temp=oPC;
TestValue=GetLocalInt(Temp, Varname);
break;
}
}
ReturnValue=( ((Type&1) && TestValue) || (!(Type&1) && !TestValue) );
}
return ReturnValue;
}
int CheckIfPCMeetsGenderCriteria(object oPC, string SubraceStorage)
{
int iFlag = GetSSEInt( SubraceStorage + "_" + SUBRACE_GENDER_RES);
int PCGender = GetGender(oPC);
switch(PCGender)
{
case GENDER_MALE: PCGender = FLAG2; break;
case GENDER_FEMALE: PCGender = FLAG1; break;
default: break;
}
return !(iFlag & PCGender);
}
int CheckIfPCMeetsClassCriteria(object oPC, string SubraceStorage)
{
int PCClass = GetClassByPosition(1, oPC);
int canBeBarbarian = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, FLAG2);
int canBeBard = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, FLAG3);
int canBeCleric = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, FLAG4);
int canBeDruid = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, FLAG5);
int canBeFighter = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, FLAG6);
int canBeMonk = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, FLAG7);
int canBePaladin = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, FLAG8);
int canBeRanger = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, FLAG9);
int canBeRogue = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, FLAG10);
int canBeSorcerer = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, FLAG11);
int canBeWizard = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, FLAG12);
//longest return ever!
return ((PCClass == CLASS_TYPE_BARBARIAN && canBeBarbarian) || (PCClass == CLASS_TYPE_BARD && canBeBard) || (PCClass == CLASS_TYPE_CLERIC && canBeCleric) || (PCClass == CLASS_TYPE_DRUID && canBeDruid) || (PCClass == CLASS_TYPE_FIGHTER && canBeFighter) || (PCClass == CLASS_TYPE_MONK && canBeMonk) || (PCClass == CLASS_TYPE_PALADIN && canBePaladin) || (PCClass == CLASS_TYPE_RANGER && canBeRanger) || (PCClass == CLASS_TYPE_ROGUE && canBeRogue) || (PCClass == CLASS_TYPE_SORCERER && canBeSorcerer) || (PCClass == CLASS_TYPE_WIZARD && canBeWizard));
}
int CheckIfPCMeetsPrestigiousClassCriteria(object oPC, string SubraceStorage)
{
int MinLevel = GetSSEInt( SubraceStorage + "_" + SUBRACE_PRESTIGIOUS_CLASS_RESTRICTION_MINIMUM_LEVELS);
int iClassType = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_PRESTIGIOUS_CLASS_RESTRICTION,
MEDIUMGROUP1|TINYGROUP3);
int i=2;
int iMatch;
for( ; i < 4; i++)
{
iMatch = PrestigeClassToFlags(GetClassByPosition(i, oPC) );
if(iMatch & iClassType)
{
MinLevel -= GetLevelByPosition(i, oPC);
}
}
//Returns TRUE if MinLevel is less than or equal to 0 (we have the exact or more levels than req.)
return (MinLevel<1);
}
int CheckIfPCMeetsAlignmentCriteria(object oPC, string SubraceStorage)
{
int PCAlign1 = GetAlignmentGoodEvil(oPC);
int PCAlign2 = GetAlignmentLawChaos(oPC);
int align1 = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG2);
int align2 = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG3);
int align3 = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG4);
int align4 = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG5);
int align5 = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG6);
int align6 = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG7);
return ((PCAlign1 == ALIGNMENT_GOOD && align1) || (PCAlign1 == ALIGNMENT_NEUTRAL && align2) || (PCAlign1 == ALIGNMENT_EVIL && align3))
&&
((PCAlign2 == ALIGNMENT_LAWFUL && align4) || (PCAlign2 == ALIGNMENT_NEUTRAL && align5) || (PCAlign2 == ALIGNMENT_CHAOTIC && align6));
}
int CheckIfPCGetsAnyErrorsWithSubraceTest(object oPC, int ID)
{
int Error=0;
string SubraceStorage;
//Check if the subrace exists.
if(ID)
{
SubraceStorage = GetSubraceStorageLocationByID(ID);
int IsPrestigious = GetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_PRESTIGIOUS_SUBRACE, SUBRACE_BASE_INFORMATION_FLAGS);
if(IsPrestigious && GetPlayerLevel(oPC) == 1)
{
Error |= SUBRACE_ERROR_PRESTIGE_FAILURE;
}
else if(IsPrestigious)
{
//What (if any) is the Class Restriction
if(GetSSEInt( SubraceStorage + "_" + SUBRACE_PRESTIGIOUS_CLASS_RESTRICTION))
{
if(!CheckIfPCMeetsPrestigiousClassCriteria(oPC, SubraceStorage))
{
Error |=SUBRACE_ERROR_PRESTIGE_NOT_MET;
}
}
}
//Check if we meet Race Req.
if(!CheckIfPCMeetsBaseRaceCriteria(oPC, SubraceStorage))
{
Error |= SUBRACE_ERROR_RACE;
}
if(GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG1))
{
//Check if we meet Alignments Req.
if(!CheckIfPCMeetsAlignmentCriteria(oPC, SubraceStorage))
{
Error |= SUBRACE_ERROR_ALIGNMENT;
}
}
if(GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, FLAG1))
{
//Check if we meet Class Req.
if(!CheckIfPCMeetsClassCriteria(oPC,SubraceStorage))
{
Error |=SUBRACE_ERROR_CLASS;
}
}
if(GetSSEInt( SubraceStorage + "_" + SUBRACE_GENDER_RES) > 0)
{
if(!CheckIfPCMeetsGenderCriteria(oPC, SubraceStorage))
{
Error |= SUBRACE_ERROR_GENDER;
}
}
if(!CheckIfPCMeetsSpecialCriteria(oPC, SubraceStorage))
{
Error |= SUBRACE_ERROR_SPECIAL_RESTRICTION;
}
} //FAILED TO FIND ANY SUCH SUBRACE
else { Error = SUBRACE_ERROR_UNRECOGNISED; }
return Error;
}
int CheckIfPCMeetsAnySubraceCriteria(object oPC)
{
string subrace = GetSubRace(oPC);
int ID = GetSubraceID(subrace);
int Error = CheckIfPCGetsAnyErrorsWithSubraceTest(oPC, ID);
int i=1;
string sErrorMessage;
if((Error & SUBRACE_ERROR_UNRECOGNISED))
{
SSE_MessageHandler(oPC, MESSAGE_SUBRACE_UNRECOGNISED, subrace);
return SUBRACE_UNRECOGNISED;
}
else if(Error > 0)
{
string sMsg = FlagNumberToErrorMSG(Error);
SSE_MessageHandler(oPC, MESSAGE_SUBRACE_CRITERIA_FAILED, sMsg);
SetSubRace(oPC, "");
SSE_MessageHandler(oPC, MESSAGE_SUBRACE_FAILED_CRITERIA_SO_REMOVED);
}
else SSE_MessageHandler(oPC, MESSAGE_SUBRACE_CRITERIA_MET);
return !(Error > 0);
}
string GetTemporarySubraceSkin(object oPC, string SubraceStorage, int iTime)
{
int Level = GetPlayerLevel(oPC);
string SkinResRef;
while(Level > 0)
{
string resref = GetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_SKIN + "_" + IntToString(Level) + "_" + IntToString(iTime));
if(resref != "")
{
SkinResRef = resref;
break;
}
Level--;
}
return SkinResRef;
}
//::****************************************************************
// 1.69 -- Returns TRUE if oSkin is valid and has the Horse Menu Feat on it. Returns FALSE otherwise.
int GetSkinHasHorseMenu( object oSkin)
{ if( !GetIsObjectValid( oSkin)) return FALSE;
itemproperty ipHorseMenu = GetFirstItemProperty( oSkin);
while( GetIsItemPropertyValid( ipHorseMenu))
{ if( (GetItemPropertyType( ipHorseMenu) == ITEM_PROPERTY_BONUS_FEAT) &&
(GetItemPropertySubType( ipHorseMenu) == IP_CONST_HORSE_MENU_SSE))
return TRUE;
ipHorseMenu = GetNextItemProperty( oSkin);
}
return FALSE;
}
//::****************************************************************
void EquipTemporarySubraceSkin(string SubraceStorage, object oPC, int iTime)
{
string sSkin = GetTemporarySubraceSkin(oPC, SubraceStorage, iTime);
if(sSkin == "")
{
sSkin = GetTemporarySubraceSkin(oPC, SubraceStorage, TIME_BOTH);
}
object ExistingSkin = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oPC);
string ResrefExistingSkin = GetResRef(ExistingSkin);
if(ResrefExistingSkin != sSkin)
{
object NewSkin = CreateItemOnObject(sSkin, oPC);
//::****************************************************************
// 1.69 -- Add horse menu to new skin if needed
if( (GetIsPC( oPC) || GetIsDM( oPC)) && !GetSkinHasHorseMenu( NewSkin) &&
((!GetIsObjectValid( ExistingSkin) && !GetHasFeat( FEAT_HORSE_MENU, oPC)) ||
GetSkinHasHorseMenu( ExistingSkin)) )
{ itemproperty iProp = ItemPropertyBonusFeat( IP_CONST_HORSE_MENU_SSE);
AddItemProperty( DURATION_TYPE_PERMANENT, iProp, NewSkin);
}
//::****************************************************************
if(GetIsObjectValid(ExistingSkin))
{
SetPlotFlag(ExistingSkin, FALSE);
DestroyObject(ExistingSkin, 0.2);
}
SetIdentified(NewSkin, TRUE);
DelayCommand(1.0, AssignCommand(oPC, SHA_SubraceForceEquipItem(NewSkin, INVENTORY_SLOT_CARMOUR)));
}
}
string GetTemporarySubraceClaw(object oPC, string SubraceStorage, string Claw, int iTime)
{
int Level = GetPlayerLevel(oPC);
string ClawResRef = "";
while(Level > 0)
{
string resref = GetLocalString(oStorer, SubraceStorage + "_" + Claw + "_" + IntToString(Level) + "_" + IntToString(iTime));
if(resref != "")
{
ClawResRef = resref;
break;
}
Level--;
}
return ClawResRef;
}
void EquipTemporarySubraceClaw(string SubraceStorage, object oPC, int iTime)
{
string sLeftClaw = GetTemporarySubraceClaw(oPC, SubraceStorage, SUBRACE_LEFT_CLAW, iTime);
string sRightClaw = GetTemporarySubraceClaw(oPC, SubraceStorage, SUBRACE_RIGHT_CLAW, iTime);
if(sLeftClaw == "")
{
sLeftClaw = GetTemporarySubraceClaw(oPC, SubraceStorage, SUBRACE_LEFT_CLAW, TIME_BOTH);
}
if(sRightClaw == "")
{
sRightClaw = GetTemporarySubraceClaw(oPC, SubraceStorage, SUBRACE_RIGHT_CLAW, TIME_BOTH);
}
object ExistingLeftClaw = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oPC);
object ExistingRightClaw = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oPC);
string ResrefExistingLClaw = GetStringLowerCase(GetResRef(ExistingLeftClaw));
string ResrefExistingRClaw = GetStringLowerCase(GetResRef(ExistingRightClaw));
if((ResrefExistingRClaw != sRightClaw) || (ResrefExistingLClaw != sLeftClaw))
{
SSE_MessageHandler(oPC, MESSAGE_SUBRACE_CLAWS_WAIT_FOR_CLAWS_EQUIPPING);
if(!GetHasFeat(FEAT_WEAPON_PROFICIENCY_CREATURE, oPC))
{
SSE_MessageHandler(oPC, MESSAGE_SUBRACE_CLAWS_MISSING_CREATURE_WEAPON_PROFICIENCY);
return;
}
DelayCommand(9.0, SSE_MessageHandler(oPC,MESSAGE_SUBRACE_CLAWS_SUCCESSFULLY_EQUIPPED));
}
if(ResrefExistingRClaw != sRightClaw)
{
object NewRClaw = CreateItemOnObject(sRightClaw, oPC);
if(sRightClaw == "none" || GetIsObjectValid(ExistingRightClaw))
{
SetPlotFlag(ExistingRightClaw, FALSE);
DestroyObject(ExistingRightClaw, 0.2);
}
SetIdentified(NewRClaw, TRUE);
DelayCommand(1.0, AssignCommand(oPC, SHA_SubraceForceEquipItem(NewRClaw, INVENTORY_SLOT_CWEAPON_R)));
}
if(ResrefExistingLClaw != sLeftClaw)
{
object NewLClaw = CreateItemOnObject(sLeftClaw, oPC);
if(sLeftClaw == "none" || GetIsObjectValid(ExistingLeftClaw))
{
SetPlotFlag(ExistingLeftClaw, FALSE);
DestroyObject(ExistingLeftClaw, 0.3);
}
SetIdentified(NewLClaw, TRUE);
DelayCommand(5.0, AssignCommand(oPC, SHA_SubraceForceEquipItem(NewLClaw, INVENTORY_SLOT_CWEAPON_L)));
}
}
void SearchAndDestroySkinsAndClaws(object oPC)
{
object oItem = GetFirstItemInInventory(oPC);
while(GetIsObjectValid(oItem))
{
int iType = GetBaseItemType(oItem);
if(iType == BASE_ITEM_CREATUREITEM || iType == BASE_ITEM_CPIERCWEAPON || iType == BASE_ITEM_CSLASHWEAPON || iType == BASE_ITEM_CSLSHPRCWEAP)
{
SetPlotFlag(oItem, FALSE);
DestroyObject(oItem, 0.1);
}
oItem = GetNextItemInInventory(oPC);
}
}
void GiveSubraceUniqueItem(string SubraceStorage, object oPC)
{
int i = 0;
int iLevel = GetPlayerLevel(oPC);
int iChk = GetSubraceDBInt(SUBRACE_DATABASE, SubraceStorage + "_" + SUBRACE_UNIQUEITEM, oPC);
if(iChk > iLevel)
{ return; }
i = iChk;
int SubraceUniqueItemCount = GetSSEInt( SubraceStorage + "_" + SUBRACE_UNIQUEITEM_COUNT);
while(i <= SubraceUniqueItemCount)
{
i++;
string resref = GetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_UNIQUEITEM + "_" + IntToString(i));
if(resref != "")
{
string sLevel = GetStringRight(resref, 2);
if(GetStringLeft(sLevel, 1) == "_")
{
//resref: itemref_1
sLevel = GetStringRight(sLevel, 1);
resref = GetStringLeft(resref, GetStringLength(resref) - 2);
}
else
{
//resref: itemref_12
resref = GetStringLeft(resref, GetStringLength(resref) - 3);
}
int iLvl = StringToInt(sLevel);
if(iLvl == iLevel)
{
object oItem = CreateItemOnObject(resref, oPC, 1);
DelayCommand(1.0, SSE_MessageHandler(oPC, MESSAGE_SUBRACE_ACQUIRED_UNIQUE_ITEM, GetName(oItem)));
SetSubraceDBInt(SUBRACE_DATABASE, SubraceStorage + "_" + SUBRACE_UNIQUEITEM, iLevel, oPC);
SetIdentified(oItem, TRUE);
SetPlotFlag(oItem, TRUE);
SetItemCursedFlag(oItem, TRUE);
}
}
}
}
void CheckAndGiveSubraceItems(object oPC)
{
string SubraceStorage = GetSubraceStorageLocation(GetSubRace(oPC));
GiveSubraceUniqueItem(SubraceStorage, oPC);
}
int SHA_GetDefaultAppearanceType(object oPC)
{
int iRace = GetRacialType(oPC);
int DefaultAppearance;
switch(iRace)
{
case RACIAL_TYPE_DWARF: DefaultAppearance = APPEARANCE_TYPE_DWARF; break;
case RACIAL_TYPE_ELF: DefaultAppearance = APPEARANCE_TYPE_ELF; break;
case RACIAL_TYPE_GNOME: DefaultAppearance = APPEARANCE_TYPE_GNOME; break;
case RACIAL_TYPE_HALFELF: DefaultAppearance = APPEARANCE_TYPE_HALF_ELF; break;
case RACIAL_TYPE_HALFLING: DefaultAppearance = APPEARANCE_TYPE_HALFLING; break;
case RACIAL_TYPE_HALFORC: DefaultAppearance = APPEARANCE_TYPE_HALF_ORC; break;
case RACIAL_TYPE_HUMAN: DefaultAppearance = APPEARANCE_TYPE_HUMAN; break;
default: DefaultAppearance = APPEARANCE_TYPE_HUMAN; break;
}
return DefaultAppearance;
}
int Subrace_GetFavouredClass(object oPC)
{
return GetLocalInt(oPC, SUBRACE_FAVORED_CLASS) - 1;
}
int GetRacialFavoredClass(int Race)
{
int Class = CLASS_TYPE_NONE;
switch(Race)
{
case RACIAL_TYPE_DWARF: Class = CLASS_TYPE_FIGHTER; break;
case RACIAL_TYPE_HUMAN: Class = CLASS_TYPE_ANY; break;
case RACIAL_TYPE_ELF: Class = CLASS_TYPE_WIZARD; break;
case RACIAL_TYPE_GNOME: Class = CLASS_TYPE_WIZARD; break;
case RACIAL_TYPE_HALFELF: Class = CLASS_TYPE_ANY; break;
case RACIAL_TYPE_HALFORC: Class = CLASS_TYPE_BARBARIAN; break;
case RACIAL_TYPE_HALFLING: Class = CLASS_TYPE_ROGUE; break;
}
return Class;
}
void LoadSubraceFromScript(string Script, int Conditions=SSE_SUBRACE_LOADER_CONDITION_ALWAYS_LOAD)
{
int Load=TRUE, Timer=0;
switch(Conditions)
{
case SSE_SUBRACE_LOADER_CONDITION_LOAD_IF_USING_LETO:
Load=ENABLE_LETO;
break;
case SSE_SUBRACE_LOADER_CONDITION_LOAD_IF_NOT_USING_LETO:
Load=(!ENABLE_LETO);
break;
default:
Load=TRUE;
break;
}
if(Load)
{
Timer = GetSSEInt( SSE_SUBRACE_LOADER_AMOUNT);
Timer++;
SetSSEInt( SSE_SUBRACE_LOADER_AMOUNT, Timer);
//A flat 0.0 delay will make the Sub-race script a separate instance.
//But I suppose it never hurt anyone giving the module a little time...
//10ms per script should do for any decent CPU.
DelayCommand(Timer/100.0, ExecuteScript(Script, oStorer));
}
}
void SetSSEInt(string VariableName, int Value)
{
SetLocalInt(oStorer, VariableName, Value);
}
int GetSSEInt(string VariableName)
{
return GetLocalInt(oStorer, VariableName);
}
void DeleteSSEInt(string VariableName)
{
DeleteLocalInt(oStorer, VariableName);
}
void SSE_ModuleLoadEvent(int doNWNXInit=FALSE)
{
if(doNWNXInit)
{
//Just do this instantly, other external processes may be depent of each.
SetLocalString(oStorer, "NWNX!INIT", "1");
}
int Scripts=GetSSEInt(SSE_SUBRACE_LOADER_AMOUNT);
int Subraces=GetSSEInt( MODULE_SUBRACE_COUNT);
int Delays=GetSSEInt(SSE_SUBRACE_LOADER_AMOUNT_OF_DELAYS);
//If no scripts or no subraces have been found, then this is probably triggered
//before our subrace load scripts.
if(!Scripts && !Subraces && Delays<4)
{
Delays++;
SetSSEInt(SSE_SUBRACE_LOADER_AMOUNT_OF_DELAYS, Delays);
DelayCommand(10.0, SSE_ModuleLoadEvent());
}
//if subraces / scripts have been found, give additional 5 seconds to load the
//remaining files.
else if(!(Delays&0x80000000) )
{
Delays|=0x80000000;
DelayCommand(5.0, SSE_ModuleLoadEvent());
SetSSEInt(SSE_SUBRACE_LOADER_AMOUNT_OF_DELAYS, Delays);
}
//Okay, all subraces should be loaded by now.
else
{
//Calculate time we waited for subraces to load, since this was triggered.
if(Delays&0x80000000)
{
Delays= ((( (Delays&(~0x80000000) ) )<<1) +1 )*5;
}
else
{
Delays*=10;
}
string Output = "*Subrace Engine: Module load completed" +
"\n - Loaded " + IntToString(Subraces) + " subraces." +
"\n - Scripts Executed: " + IntToString(Scripts) +
"\n - Waited " + IntToString(Delays) + " seconds.";
if(SUBRACE_SPELLHOOKS!="")
{
//Use spellhooks
SetModuleOverrideSpellscript(SUBRACE_SPELLHOOKS);
Output +="\n - Spellhook: " + SUBRACE_SPELLHOOKS;
}
Output += "\n NWNX info:";
if(ENABLE_LETO)
{
Output += "\n - Leto Enabled - testing NWNX connection..."+
"\n - Leto is ";
if(LetoPingPong())
{
Output += "replying.";
}
else
{
Output += "NOT working!";
}
}
else
{
Output += "\n - Leto Disabled";
}
Output += "\n - NWNX Database " +(ENABLE_NWNX_DATABASE?"enabled":"disabled")+ ".";
SetSSEInt( SUBRACE_INFO_LOADED_ON_MODULE, TRUE);
Output += "\nEnd of Module Load summary";
WriteTimestampedLogEntry(Output);
Output = "List of loaded sub-races loaded";
int i=1;
for( ; i<= Subraces ; i++)
Output += "\n - " + GetSubraceNameByID(i);
WriteTimestampedLogEntry(Output);
DeleteSSEInt(SSE_SUBRACE_LOADER_AMOUNT);
DeleteSSEInt(SSE_SUBRACE_LOADER_AMOUNT_OF_DELAYS);
}
}
int GetFavoredClassExceedsGap(int Race1Favored, int Race2Favored, int Class1, int Class2, int Class3, int Class13Gap, int Class23Gap, int Class12Gap)
{
//Has PC got Race 1 Favored class?
int iR1Class1Favored = FALSE;
int iR1Class2Favored = FALSE;
int iR1Class3Favored = FALSE;
//Has PC got Race 2 Favored class?
int iR2Class1Favored = FALSE;
int iR2Class2Favored = FALSE;
int iR2Class3Favored = FALSE;
if(Race1Favored == Class1)
{
iR1Class1Favored = TRUE;
}
if(Race1Favored == Class2 && Class2 != CLASS_TYPE_INVALID)
{
iR1Class2Favored = TRUE;
}
if(Race1Favored == Class3 && Class3 != CLASS_TYPE_INVALID)
{
iR1Class3Favored = TRUE;
}
if(Race2Favored == Class1)
{
iR2Class1Favored = TRUE;
}
if(Race2Favored == Class2 && Class2 != CLASS_TYPE_INVALID)
{
iR2Class2Favored = TRUE;
}
if(Race2Favored == Class3 && Class3 != CLASS_TYPE_INVALID)
{
iR2Class3Favored = TRUE;
}
int Exceed12 = FALSE;
int Exceed13 = FALSE;
int Exceed23 = FALSE;
int iResult12 = FALSE;
int iResult13 = FALSE;
int iResult23 = FALSE;
if(abs(Class12Gap) >=2)
{
Exceed12 = TRUE;
}
else if(abs(Class13Gap) >=2)
{
Exceed13 = TRUE;
}
else if(abs(Class23Gap) >=2)
{
Exceed23 = TRUE;
}
if(Exceed12)
{
if(iR1Class1Favored || iR1Class2Favored)
{
iResult12 = TRUE;
if((iR2Class1Favored && Class3 != CLASS_TYPE_INVALID) || (iR2Class2Favored && Class3 != CLASS_TYPE_INVALID))
{
iResult12 = FALSE;
}
}
}
if(Exceed13)
{
if(iR1Class1Favored || iR1Class3Favored)
{
iResult13 = TRUE;
if(iR2Class1Favored ||iR2Class3Favored)
{
iResult13 = FALSE;
}
}
}
if(Exceed23)
{
if(iR1Class2Favored || iR1Class3Favored)
{
iResult23 = TRUE;
if(iR2Class2Favored ||iR2Class3Favored)
{
iResult23 = FALSE;
}
}
}
return (iResult12 || iResult13 || iResult23);
}
int XPPenaltyOrBoostForSubrace(object oPC, int FClass)
{
int iRace = GetRacialType(oPC);
int iRFavored = GetRacialFavoredClass(iRace);
int iSFavored = FClass;
if(iSFavored == iRFavored)
{
return SUBRACE_XP_UNCHANGED;
}
int Class1 = GetClassByPosition(1, oPC);
int Class2 = GetClassByPosition(2, oPC);
int Class3 = GetClassByPosition(3, oPC);
int Class1Level = GetLevelByClass(Class1, oPC);
int Class2Level = GetLevelByClass(Class2, oPC);
int Class3Level = GetLevelByClass(Class3, oPC);
if(iRFavored == CLASS_TYPE_ANY)
{
int Max1 = Max(Class1Level, Class2Level);
int Max2 = Max(Max1, Class3Level);
if(Max2 == Class1Level)
{
iRFavored = Class1;
}
else if(Max2 == Class2Level)
{
iRFavored = Class2;
}
else if(Max2 == Class3Level)
{
iRFavored = Class3;
}
}
if(iSFavored == CLASS_TYPE_ANY)
{
int Max1 = Max(Class1Level, Class2Level);
int Max2 = Max(Max1, Class3Level);
if(Max2 == Class1Level)
{
iSFavored = Class1;
}
else if(Max2 == Class2Level)
{
iSFavored = Class2;
}
else if(Max2 == Class3Level)
{
iSFavored = Class3;
}
}
int Class12Gap = Class1Level - Class2Level;
int Class13Gap = Class1Level - Class3Level;
int Class23Gap = Class2Level - Class3Level;
if(Class2Level == 0)
{
Class12Gap = 0;
Class23Gap = 0;
}
if(Class3Level == 0)
{
Class13Gap = 0;
}
int SubraceFClassExcGap = FALSE;
int RacialFClassExcGap = FALSE;
if(SUBRACE_IGNORE_BASE_RACE_FAVORED_CLASS)
{
RacialFClassExcGap = GetFavoredClassExceedsGap(iRFavored, iSFavored, Class1, Class2, Class3, Class13Gap, Class23Gap, Class12Gap);
}
SubraceFClassExcGap = GetFavoredClassExceedsGap(iSFavored, iRFavored, Class1, Class2, Class3, Class13Gap, Class23Gap, Class12Gap);
//Racial Favored Class Exceeds the Multiclass Level gap, and Subrace Favored class does not
//So give a decrease in XP to counter NWN engine XP distribution.
if(RacialFClassExcGap && !SubraceFClassExcGap)
{
return SUBRACE_XP_DECREASE;
}
//Subrace Favored Class Exceeds the Multiclass Level gap, and Racial Favored class does not
//So give a boost in XP to override the NWN engine XP distribution.
else if(!RacialFClassExcGap && SubraceFClassExcGap)
{
return SUBRACE_XP_BOOST;
}
//Both exceed the Multiclass Level gap or do not.
//So since the effects of both exceeding cancel each other out, return normal XP.
return SUBRACE_XP_UNCHANGED;
}
float GetSubraceXPModifier(object oPC)
{
int FClass = Subrace_GetFavouredClass(oPC);
float iMod = 1.0;
if(FClass != -1)
{
int XPMod = XPPenaltyOrBoostForSubrace(oPC, FClass);
if(XPMod == SUBRACE_XP_BOOST)
{
iMod = 1.25;
}
else if(XPMod == SUBRACE_XP_DECREASE)
{
iMod = 0.8;
}
}
return iMod;
}
int GetECL(object oPC)
{
string SubraceStorage = GetSubraceStorageLocationByID(GetPlayerSubraceID(oPC));
return GetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_ECL);
}
int Subrace_GetIsUndead(object oPC)
{
if(!GetIsPC(oPC)) { return FALSE; }
int ID = GetPlayerSubraceID(oPC);
if(!ID) { return FALSE; }
string SubraceStorage = GetSubraceStorageLocationByID(ID);
return GetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_UNDEAD, SUBRACE_BASE_INFORMATION_FLAGS);
}
void ApplyUniqueSubraceEffect(object oPC, string SubraceStorage, int iEffect)
{
if(iEffect == 0)
{ return; }
int Value1 = GetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_EFFECT,SUBRACE_EFFECT_VALUE1_FLAGSET);
int Value2 = GetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_EFFECT,SUBRACE_EFFECT_VALUE2_FLAGSET);
int DurationType = GetSSEInt( SubraceStorage + "_" + SUBRACE_EFFECT_DURATION_TYPE);
float fDuration = GetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_EFFECT_DURATION);
effect eEffect = SHA_GetEffectFromID(iEffect, Value1, Value2);
effect eEffectApp = SupernaturalEffect(eEffect);
AssignCommand(oStorer, ApplyEffectToObject(DurationType, eEffectApp, oPC, fDuration));
}
void ApplySubraceEffect(object oPC, string SubraceStorage, int TimeOfDay)
{
int EffectCount = GetSSEInt( SubraceStorage + "_" + SUBRACE_EFFECT_COUNT);
if(EffectCount == 0)
{
return;
}
ClearSubraceEffects(oPC);
int i = 0;
while(i != EffectCount)
{
i++;
string SubraceStorage1 = SubraceStorage + IntToString(i);
int EffectID = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + SUBRACE_EFFECT,SUBRACE_EFFECT_FLAGSET);
int EffectTimeOfDay = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + SUBRACE_EFFECT,SUBRACE_EFFECT_TIME_FLAGSET);
if(EffectTimeOfDay == TIME_BOTH || EffectTimeOfDay == TimeOfDay)
{
ApplyUniqueSubraceEffect(oPC, SubraceStorage1, EffectID);
}
}
SSE_MessageHandler(oPC, MESSAGE_SUBRACE_EFFECTS_APPLIED);
}
void ApplySubrace(object oTarget, string subrace)
{
subrace = GetStringLowerCase(subrace);
if(ENABLE_LETO)
{
SetLocalString(oTarget, "SUBR_PlayerName", GetPCPlayerName(oTarget));
DelayCommand(4.0, SetLocalString(oTarget, "SUBR_FileName", GetBicFileName(oTarget)));
}
DeleteSubraceInfoOnPC(oTarget);
int ID = GetSubraceID(subrace);
DelayCommand(1.5, LoadSubraceInfoOnPC(oTarget, subrace));
DelayCommand(2.6, SetSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + "_" + GetSubraceNameByAlias(subrace, TRUE), SUBRACE_ACCEPTED, oTarget));
DelayCommand(4.0, ApplyPermanentSubraceSpellResistance(ID, oTarget));
DelayCommand(5.5, ApplyPermanentSubraceAppearance(ID, oTarget));
// 3.0.6.6
DelayCommand(6.0, ApplySubraceColors(oTarget));
DelayCommand(6.5, ApplySubraceEyeColors(oTarget));
//3.0.6.9
DelayCommand(7.0, ApplySubraceHead(oTarget));
DelayCommand(7.5, CheckIfCanUseEquipedWeapon(oTarget));
DelayCommand(11.5,CheckIfCanUseEquippedArmor(oTarget));
}
//3.0.6.6
void ApplySubraceColors(object oPC)
{
string SubraceStorage = GetSubraceStorageLocation(GetStringLowerCase(GetSubRace(oPC)));
int Level = GetPlayerLevel(oPC);
while (Level)
{
string SubraceStorage1 = SubraceStorage + "_" + IntToString(Level);
int Gender = GetGender(oPC);
if(GetSSEInt( SubraceStorage1 + "_" + SUBRACE_COLORS_FLAGS) )
{
int Hair = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + SUBRACE_COLORS_FLAGS, (Gender==GENDER_MALE?SUBRACE_COLORS_FLAGS_HAIR_MALE:SUBRACE_COLORS_FLAGS_HAIR_FEMALE) );
int Skin = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + SUBRACE_COLORS_FLAGS, (Gender==GENDER_MALE?SUBRACE_COLORS_FLAGS_SKIN_MALE:SUBRACE_COLORS_FLAGS_SKIN_FEMALE) );
if ((Hair>-1)||(Skin>-1))
{
if (Hair>-1)
{
SetColor(oPC, COLOR_CHANNEL_HAIR, Hair);
}
if (Skin>-1)
{
SetColor(oPC, COLOR_CHANNEL_SKIN, Skin);
}
return;
}
}
Level--;
}
}
//3.0.6.6
void SHA_SetEyeColor(object oPC, int iEyes = -1)
{
effect eEffect, eVisEyes;
int iGender = GetGender(oPC), iSub, iType;
switch (iEyes)
{
case SSE_EYE_COLOR_CYAN:
{
switch(GetRacialType(oPC))
{
case RACIAL_TYPE_DWARF:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_CYN_DWARF_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_CYN_DWARF_FEMALE);
break;
}
case RACIAL_TYPE_ELF:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_CYN_ELF_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_CYN_ELF_FEMALE);
break;
}
case RACIAL_TYPE_GNOME:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_CYN_GNOME_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_CYN_GNOME_FEMALE);
break;
}
case RACIAL_TYPE_HALFELF:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_CYN_HUMAN_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_CYN_HUMAN_FEMALE);
break;
}
case RACIAL_TYPE_HALFLING:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_CYN_HALFLING_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_CYN_HALFLING_FEMALE);
break;
}
case RACIAL_TYPE_HALFORC:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_CYN_HALFORC_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_CYN_HALFORC_FEMALE);
break;
}
case RACIAL_TYPE_HUMAN:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_CYN_HUMAN_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_CYN_HUMAN_FEMALE);
break;
}
}
break;
}
case SSE_EYE_COLOR_GREEN:
{
switch(GetRacialType(oPC))
{
case RACIAL_TYPE_DWARF:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_DWARF_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_DWARF_FEMALE);
break;
}
case RACIAL_TYPE_ELF:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_ELF_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_ELF_FEMALE);
break;
}
case RACIAL_TYPE_GNOME:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_GNOME_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_GNOME_FEMALE);
break;
}
case RACIAL_TYPE_HALFELF:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_HUMAN_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_HUMAN_FEMALE);
break;
}
case RACIAL_TYPE_HALFLING:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_HALFLING_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_HALFLING_FEMALE);
break;
}
case RACIAL_TYPE_HALFORC:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_HALFORC_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_HALFORC_FEMALE);
break;
}
case RACIAL_TYPE_HUMAN:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_HUMAN_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_HUMAN_FEMALE);
break;
}
}
break;
}
case SSE_EYE_COLOR_ORANGE:
{
switch(GetRacialType(oPC))
{
case RACIAL_TYPE_DWARF:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_ORG_DWARF_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_ORG_DWARF_FEMALE);
break;
}
case RACIAL_TYPE_ELF:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_ORG_ELF_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_ORG_ELF_FEMALE);
break;
}
case RACIAL_TYPE_GNOME:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_ORG_GNOME_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_ORG_GNOME_FEMALE);
break;
}
case RACIAL_TYPE_HALFELF:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_ORG_HUMAN_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_ORG_HUMAN_FEMALE);
break;
}
case RACIAL_TYPE_HALFLING:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_ORG_HALFLING_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_ORG_HALFLING_FEMALE);
break;
}
case RACIAL_TYPE_HALFORC:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_ORG_HALFORC_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_ORG_HALFORC_FEMALE);
break;
}
case RACIAL_TYPE_HUMAN:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_ORG_HUMAN_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_ORG_HUMAN_FEMALE);
break;
}
}
break;
}
case SSE_EYE_COLOR_PURPLE:
{
switch(GetRacialType(oPC))
{
case RACIAL_TYPE_DWARF:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_PUR_DWARF_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_PUR_DWARF_FEMALE);
break;
}
case RACIAL_TYPE_ELF:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_PUR_ELF_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_PUR_ELF_FEMALE);
break;
}
case RACIAL_TYPE_GNOME:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_PUR_GNOME_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_PUR_GNOME_FEMALE);
break;
}
case RACIAL_TYPE_HALFELF:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_PUR_HUMAN_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_PUR_HUMAN_FEMALE);
break;
}
case RACIAL_TYPE_HALFLING:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_PUR_HALFLING_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_PUR_HALFLING_FEMALE);
break;
}
case RACIAL_TYPE_HALFORC:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_PUR_HALFORC_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_PUR_HALFORC_FEMALE);
break;
}
case RACIAL_TYPE_HUMAN:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_PUR_HUMAN_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_PUR_HUMAN_FEMALE);
break;
}
}
break;
}
case SSE_EYE_COLOR_RED:
{
switch(GetRacialType(oPC))
{
case RACIAL_TYPE_DWARF:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_DWARF_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_DWARF_FEMALE);
break;
}
case RACIAL_TYPE_ELF:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_ELF_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_ELF_FEMALE);
break;
}
case RACIAL_TYPE_GNOME:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_GNOME_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_GNOME_FEMALE);
break;
}
case RACIAL_TYPE_HALFELF:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_HALFELF_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_HALFELF_FEMALE);
break;
}
case RACIAL_TYPE_HALFLING:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_HALFLING_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_HALFLING_FEMALE);
break;
}
case RACIAL_TYPE_HALFORC:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_HALFORC_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_HALFORC_FEMALE);
break;
}
case RACIAL_TYPE_HUMAN:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_HUMAN_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_HUMAN_FEMALE);
break;
}
}
break;
}
case SSE_EYE_COLOR_WHITE:
{
switch(GetRacialType(oPC))
{
case RACIAL_TYPE_DWARF:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_WHT_DWARF_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_WHT_DWARF_FEMALE);
break;
}
case RACIAL_TYPE_ELF:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_WHT_ELF_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_WHT_ELF_FEMALE);
break;
}
case RACIAL_TYPE_GNOME:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_WHT_GNOME_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_WHT_GNOME_FEMALE);
break;
}
case RACIAL_TYPE_HALFELF:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_WHT_HUMAN_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_WHT_HUMAN_FEMALE);
break;
}
case RACIAL_TYPE_HALFLING:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_WHT_HALFLING_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_WHT_HALFLING_FEMALE);
break;
}
case RACIAL_TYPE_HALFORC:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_WHT_HALFORC_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_WHT_HALFORC_FEMALE);
break;
}
case RACIAL_TYPE_HUMAN:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_WHT_HUMAN_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_WHT_HUMAN_FEMALE);
break;
}
}
break;
}
case SSE_EYE_COLOR_YELLOW:
{
switch(GetRacialType(oPC))
{
case RACIAL_TYPE_DWARF:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_YEL_DWARF_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_YEL_DWARF_FEMALE);
break;
}
case RACIAL_TYPE_ELF:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_YEL_ELF_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_YEL_ELF_FEMALE);
break;
}
case RACIAL_TYPE_GNOME:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_YEL_GNOME_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_YEL_GNOME_FEMALE);
break;
}
case RACIAL_TYPE_HALFELF:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_YEL_HUMAN_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_YEL_HUMAN_FEMALE);
break;
}
case RACIAL_TYPE_HALFLING:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_YEL_HALFLING_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_YEL_HALFLING_FEMALE);
break;
}
case RACIAL_TYPE_HALFORC:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_YEL_HALFORC_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_YEL_HALFORC_FEMALE);
break;
}
case RACIAL_TYPE_HUMAN:
{
if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_YEL_HUMAN_MALE);
else eVisEyes = EffectVisualEffect(VFX_EYES_YEL_HUMAN_FEMALE);
break;
}
}
break;
}
}
eEffect = GetFirstEffect(oPC);
while (GetIsEffectValid(eEffect))
{
iType = GetEffectType(eEffect);
iSub = GetEffectSubType(eEffect);
if (iType == EFFECT_TYPE_VISUALEFFECT && iSub == SUBTYPE_SUPERNATURAL)
{
RemoveEffect(oPC, eEffect);
}
eEffect = GetNextEffect(oPC);
}
ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(eVisEyes), oPC);
}
//3.0.6.9
void ApplySubraceHead(object oPC)
{
string SubraceStorage = GetSubraceStorageLocation(GetStringLowerCase(GetSubRace(oPC)));
int Level = GetPlayerLevel(oPC);
while (Level)
{
string SubraceStorage1 = SubraceStorage + "_" + IntToString(Level);
int Gender = GetGender(oPC);
if(GetSSEInt( SubraceStorage1 + "_" + SUBRACE_HEAD_FLAGS) )
{
int iHead = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + SUBRACE_HEAD_FLAGS, (Gender==GENDER_MALE?SUBRACE_HEAD_FLAGS_MALE:SUBRACE_HEAD_FLAGS_FEMALE) );
if (iHead>-1)
{
SetCreatureBodyPart(CREATURE_PART_HEAD,iHead,oPC);
return;
}
}
Level--;
}
}
//3.0.6.6
void ApplySubraceEyeColors(object oPC)
{
string SubraceStorage = GetSubraceStorageLocation(GetStringLowerCase(GetSubRace(oPC)));
int Level = GetPlayerLevel(oPC);
while (Level)
{
string SubraceStorage1 = SubraceStorage + "_" + IntToString(Level);
int Gender = GetGender(oPC);
if(GetSSEInt( SubraceStorage1 + "_" + SUBRACE_EYE_COLORS_FLAGS) )
{
int iEyes = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + SUBRACE_EYE_COLORS_FLAGS, (Gender==GENDER_MALE?SUBRACE_EYE_COLORS_FLAGS_MALE:SUBRACE_EYE_COLORS_FLAGS_FEMALE) );
if (iEyes>-1)
{
SHA_SetEyeColor(oPC, iEyes);
return;
}
}
Level--;
}
}
//3.0.6.9 - Rewrite by moon
void LoadSubraceInfoOnPC(object oPC, string subrace)
{
if(GetLocalInt(oPC, SUBRACE_INFO_LOADED_ON_PC))
{
ReapplySubraceAbilities(oPC);
return;
}
if(subrace == "")
{
return;
}
// subrace = GetStringLowerCase(subrace); //DATABASE req. lowercase for compatibility with < 3.0.5
//3.0.6.9 extra optimazation
int ID = GetSubraceID(subrace);
string subraceBaseName = GetSubraceNameByID(ID);
string subraceBaseNameLower = GetStringLowerCase(subraceBaseName);
//Oh oh, someone has removed the subrace! >.<
if(!ID)
{
SSE_MessageHandler(oPC, MESSAGE_SUBRACE_IS_MISSING_FROM_SERVER);
return;
}
if(!(SSE_TREAT_ALIAS_AS_SUBRACE & 1))
{
SSE_MessageHandler(oPC, MESSAGE_SUBRACE_ALIAS_UNIFORMIZING,subrace, subraceBaseName );
SetSubRace(oPC, subraceBaseName);
subrace = subraceBaseName;
}
else if (subrace != subraceBaseName)
{
SSE_MessageHandler(oPC, MESSAGE_SUBRACE_ALIAS_DIVERSITY, subraceBaseName );
}
SetSubRace(oPC, subrace);
string SubraceStorage = GetSubraceStorageLocation(subrace);
SSE_MessageHandler(oPC, MESSAGE_SUBRACE_LOADING_DATA, subrace );
int Gender = GetGender(oPC);
GiveSubraceUniqueItem(SubraceStorage, oPC);
int iTime = SHA_GetCurrentTime();
DelayCommand(3.0, SetLocalInt(oPC, SUBRACE_INFO_LOADED_ON_PC, TRUE));
DelayCommand(4.0, ApplyTemporarySubraceAppearance(SubraceStorage, oPC, iTime));
DelayCommand(4.5, ChangeMiscellaneousSubraceStuff(oPC, GetPlayerLevel(oPC)));
DelayCommand(5.5, ApplySubraceEffect(oPC, SubraceStorage, iTime));
DelayCommand(6.5, ApplyPermanentSubraceSpellResistance(ID, oPC));
DelayCommand(7.5, ApplyPermanentSubraceAppearance(ID, oPC));
//3.0.6.6
DelayCommand(8.0, ApplySubraceColors(oPC));
DelayCommand(8.5, ApplySubraceEyeColors(oPC));
//3.0.6.9
DelayCommand(9.0, ApplySubraceHead(oPC));
DelayCommand(10.0, EquipTemporarySubraceSkin(SubraceStorage, oPC, iTime));
DelayCommand(13.0, EquipTemporarySubraceClaw(SubraceStorage, oPC, iTime));
DelayCommand(14.0, SSE_MessageHandler(oPC, MESSAGE_SUBRACE_DATA_LOADED));
DelayCommand(20.0, ChangeSubraceFactions(oPC, subrace));
int Level = GetPlayerLevel(oPC);
int NeedsToRelog = CheckForLetoReLog(oPC, Level);
if(NeedsToRelog)
{
if(!LETO_ACTIVATE_PORTAL)
{
DelayCommand(24.0, PopUpDeathGUIPanel(oPC, FALSE, FALSE, 0, SUBRACE_ENGINE + SSE_GetStandardMessage(MESSAGE_LETO_PLEASE_RELOG)));
if(LETO_AUTOMATICALLY_BOOT)
{
DelayCommand(24.2, SSE_MessageHandler(oPC, MESSAGE_LETO_AUTOBOOT, IntToString(LETO_AUTOMATIC_BOOT_DELAY) ));
DelayCommand(24.2 + IntToFloat(LETO_AUTOMATIC_BOOT_DELAY), DelayBoot(oPC));
}
}
else
{
if(!LETO_PORTAL_KEEP_CHARACTER_IN_THE_SAME_PLACE)
{
DelayCommand(24.2, SSE_MessageHandler(oPC, MESSAGE_LETO_AUTOPORTAL, IntToString(LETO_AUTOMATIC_PORTAL_DELAY) ));
DelayCommand(24.2 + IntToFloat(LETO_AUTOMATIC_PORTAL_DELAY), ActivatePortal(oPC, LETO_PORTAL_IP_ADDRESS, LETO_PORTAL_SERVER_PASSWORD, LETO_PORTAL_WAYPOINT, TRUE));
}
else
{
int RandomNumber = d100(1);
string sWPTag = "WP_SUBRACE_P" + IntToString(RandomNumber);
object oWaypoint = CreateObject(OBJECT_TYPE_WAYPOINT, "nw_waypoint001", GetLocation(oPC), FALSE, sWPTag);
DelayCommand(24.2, SSE_MessageHandler(oPC, MESSAGE_LETO_DONT_PANIC_JUSTPORTING));
DelayCommand(24.2 + IntToFloat(LETO_AUTOMATIC_PORTAL_DELAY), ActivatePortal(oPC, LETO_PORTAL_IP_ADDRESS, LETO_PORTAL_SERVER_PASSWORD, sWPTag, TRUE));
DelayCommand(24.2 + IntToFloat(LETO_AUTOMATIC_PORTAL_DELAY), DestroyObject(oWaypoint, 0.1));
}
}
DelayCommand(18.0, SetSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + LETO_CHANGES_MADE_FOR_THIS_LEVEL + "_" + subraceBaseNameLower, Level, oPC));
}
}
void DeleteSubraceInfoInDatabase(object oPC, string subrace)
{
DeleteSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + LETO_CHANGES_MADE_FOR_THIS_LEVEL + "_" + subrace, oPC);
DeleteSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + subrace, oPC);
}
void DeleteSubraceInfoOnPC(object oPC, int ClearSubraceField=FALSE)
{
string subrace = GetSubRace(oPC);
string SubraceStorage = GetSubraceStorageLocation(subrace);
if(subrace == "")
{ return; }
DelayCommand(0.2, DeleteSubraceInfoInDatabase(oPC, GetSubraceNameByAlias(subrace, TRUE)));
SSE_MessageHandler(oPC, MESSAGE_SUBRACE_PURGING);
ClearSubraceTemporaryStats(oPC);
ClearSubraceEffects(oPC);
ChangeToPCDefaultAppearance(oPC);
effect iEffect = GetFirstEffect(oPC);
while(GetIsEffectValid(iEffect))
{
int iEffectType = GetEffectType(iEffect);
if(iEffectType == EFFECT_TYPE_SPELL_RESISTANCE_INCREASE ||
iEffectType == EFFECT_TYPE_SPELL_RESISTANCE_DECREASE)
{
RemoveEffect(oPC, iEffect);
}
iEffect = GetNextEffect(oPC);
}
DeleteLocalInt(oPC, SUBRACE_INFO_LOADED_ON_PC);
object Skin = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oPC);
SetPlotFlag(Skin, FALSE);
DestroyObject(Skin, 0.1);
//::****************************************************************
// 1.69 -- Add horse menu and new skin if needed
if( (GetIsPC( oPC) || GetIsDM( oPC)) &&
(GetSkinHasHorseMenu( Skin) || (!GetIsObjectValid( Skin) && !GetHasFeat( FEAT_HORSE_MENU, oPC))))
{ SSE_HorseAddHorseMenu( oPC);
}
//::****************************************************************
object ClawLeft = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oPC);
object ClawRight = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oPC);
SetPlotFlag(ClawLeft, FALSE);
SetPlotFlag(ClawRight, FALSE);
DestroyObject(ClawLeft, 0.5);
DestroyObject(ClawRight, 0.5);
int SubraceUniqueItemCount = GetSSEInt( SubraceStorage + "_" + SUBRACE_UNIQUEITEM_COUNT);
int i = 0;
while(i <= SubraceUniqueItemCount)
{
i++;
string resref = GetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_UNIQUEITEM + "_" + IntToString(i));
if(resref != "")
{
string sLevel = GetStringRight(resref, 2);
if(GetStringLeft(sLevel, 1) == "_")
{
sLevel = GetStringRight(sLevel, 1);
}
int iLevel = StringToInt(sLevel);
resref = GetStringLeft(resref, GetStringLength(resref) - 2);
if(iLevel <= GetPlayerLevel(oPC))
{
object oItem = GetFirstItemInInventory(oPC);
while(GetIsObjectValid(oItem))
{
if(GetResRef(oItem) == resref)
{
SetPlotFlag(oItem, FALSE);
DestroyObject(oItem, 0.1);
}
oItem = GetNextItemInInventory(oPC);
}
}
}
}
SetCreatureWingType(CREATURE_WING_TYPE_NONE, oPC);
SetCreatureTailType(CREATURE_TAIL_TYPE_NONE, oPC);
DeleteLocalInt(oPC, SUBRACE_TAG + "SB_NITE_OCE");
DeleteLocalInt(oPC, SUBRACE_TAG + "SB_DAY_OCE");
DeleteLocalInt(oPC, SUBRACE_IN_SPELL_DARKNESS);
DeleteLocalInt(oPC, "SUB_EFCT_D_APD");
DeleteLocalInt(oPC, "SUB_EFCT_N_APD");
DeleteLocalInt(oPC,"SB_LGHT_DMGED");
DeleteLocalInt(oPC,"SB_DARK_DMGED");
DeleteLocalInt(oPC, SUBRACE_STATS_STATUS);
if(ClearSubraceField)
{
if(subrace == "")
{
//3.0.6.5
if (USE_SSE_DEFAULT_RACES)
{
DelayCommand(0.5, SetSubRace(oPC, ""));
DelayCommand(0.6, CheckAndApplyDefaultSubrace(oPC));
}
else
{
DelayCommand(0.5, SetSubRace(oPC, ""));
}
}
}
DelayCommand(1.0, SSE_MessageHandler(oPC, MESSAGE_SUBRACE_PURGED));
}
string Subrace_TimeToString(int iTime)
{
string ret = "ERROR";
switch(iTime)
{
case TIME_DAY: ret = "Day time"; break;
case TIME_NIGHT: ret = "Night time"; break;
case TIME_BOTH: ret = "Day & Night time"; break;
case TIME_NONE: ret = "None"; break;
case TIME_SPECIAL_APPEARANCE_NORMAL: ret = "Special - Normal Appearance"; break;
case TIME_SPECIAL_APPEARANCE_SUBRACE: ret = "Special - Subrace Appearance"; break;
}
return ret;
}
void ChangePCAppearance(object oPC, string SubraceStorage)
{
int App = GetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + APPEARANCE_TO_CHANGE, (GetGender(oPC)==GENDER_MALE?APPEARANCE_CHANGE_MALE_FLAG:APPEARANCE_CHANGE_FEMALE_FLAG) );
if(App == 0)
{
SSE_MessageHandler(oPC, MESSAGE_SUBRACE_APPEARANCE_DATA_ERROR);
return;
}
if(App == GetAppearanceType(oPC))
{ return; }
if(!DISABLE_VISUAL_EFFECTS_WHEN_CHANGING_IN_APPEARANCE)
{
int Alignment = GetAlignmentGoodEvil(oPC);
int VFX_ID = VFX_IMP_UNSUMMON;
if(Alignment == ALIGNMENT_GOOD)
{
VFX_ID = VFX_IMP_GOOD_HELP;
}
else if (Alignment == ALIGNMENT_NEUTRAL)
{
VFX_ID = VFX_FNF_SUMMON_MONSTER_3;
}
else if (Alignment == ALIGNMENT_EVIL)
{
VFX_ID = VFX_IMP_EVIL_HELP;
}
effect VisualBurst = EffectVisualEffect(VFX_ID);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, VisualBurst, oPC);
}
if(PC_SCREAMS_WHEN_CHANGING_IN_APPEARANCE)
{
AssignCommand(oPC, SpeakString(SUBRACE_WORDS_SPOKEN_ON_APPEARANCE_CHANGE_TO_MONSTER));
}
SetCreatureAppearanceType(oPC, App);
if(GetAppearanceType(oPC) == App)
SSE_MessageHandler(oPC, MESSAGE_SUBRACE_APPEARANCE_CHANGED);
}
void ChangeToPCDefaultAppearance(object oPC)
{
int App = GetRacialType(oPC);
if(App == GetAppearanceType(oPC))
{ return; }
if(!DISABLE_VISUAL_EFFECTS_WHEN_CHANGING_IN_APPEARANCE)
{
int Alignment = GetAlignmentGoodEvil(oPC);
int VFX_ID = VFX_IMP_UNSUMMON;
if(Alignment == ALIGNMENT_GOOD)
{
VFX_ID = VFX_IMP_GOOD_HELP;
}
else if (Alignment == ALIGNMENT_NEUTRAL)
{
VFX_ID = VFX_FNF_SUMMON_MONSTER_3;
}
else if (Alignment == ALIGNMENT_EVIL)
{
VFX_ID = VFX_IMP_EVIL_HELP;
}
effect VisualBurst = EffectVisualEffect(VFX_ID);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, VisualBurst, oPC);
}
if(PC_SCREAMS_WHEN_CHANGING_IN_APPEARANCE)
{
AssignCommand(oPC, SpeakString(SUBRACE_WORDS_SPOKEN_ON_APPEARANCE_CHANGE_TO_DEFAULT_RACIAL_TYPE));
}
SetCreatureAppearanceType(oPC, App);
SSE_MessageHandler(oPC, MESSAGE_SUBRACE_APPEARANCE_REVERTED);
}
void ApplyPermanentSubraceAppearance(int ID, object oPC)
{
string SubraceStorage = GetSubraceStorageLocationByID(ID);
int Level = GetPlayerLevel(oPC);
while(Level)
{
string SubraceStorage1 = SubraceStorage + "_" + IntToString(Level);
int iTime = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + APPEARANCE_CHANGE, TIME_FLAGS);
if(iTime == TIME_BOTH)
{
ChangePCAppearance(oPC, SubraceStorage1);
return;
}
Level--;
}
ChangeToPCDefaultAppearance(oPC);
}
void ApplyTemporarySubraceAppearance(string SubraceStorage, object oPC, int iCurrentTime)
{
int Level = GetPlayerLevel(oPC);
while(Level)
{
string SubraceStorage1 = SubraceStorage + "_" + IntToString(Level);
int iTime = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + APPEARANCE_CHANGE, TIME_FLAGS);
if(iTime && iTime != TIME_NONE && iTime!= TIME_BOTH )
{
if(iTime == iCurrentTime)
{
ChangePCAppearance(oPC, SubraceStorage1);
}
else if(iTime != iCurrentTime)
{
ChangeToPCDefaultAppearance(oPC);
}
return;
}
Level--;
}
}
void ApplyPermanentSubraceSpellResistance(int ID, object oPC)
{
string SubraceStorage = GetSubraceStorageLocationByID(ID);
if(GetSSEInt( SubraceStorage + "_" + SUBRACE_SPELL_RESISTANCE) == 0)
{ return; }
effect iEffect = GetFirstEffect(oPC);
while(GetIsEffectValid(iEffect))
{
int iEffectType = GetEffectType(iEffect);
if(iEffectType == EFFECT_TYPE_SPELL_RESISTANCE_INCREASE ||
iEffectType == EFFECT_TYPE_SPELL_RESISTANCE_DECREASE)
{
RemoveEffect(oPC, iEffect);
}
iEffect = GetNextEffect(oPC);
}
int SpellResAtLevel1 = GetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_SPELL_RESISTANCE, SUBRACE_SPELL_RESISTANCE_BASE_FLAGS);
int SpellResAtLevelMax = GetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_SPELL_RESISTANCE, SUBRACE_SPELL_RESISTANCE_MAX_FLAGS);
float AvgSR;
effect SpellResistance;
float baseSR = IntToFloat(SpellResAtLevel1);
float maxSR = IntToFloat(SpellResAtLevelMax);
AvgSR = maxSR - baseSR;
float SRPerLevel = AvgSR/IntToFloat(MAXIMUM_PLAYER_LEVEL);
float PCLevel = IntToFloat(GetPlayerLevel(oPC));
float SR = (PCLevel*SRPerLevel)+ baseSR;
int SR_int = FloatToInt(SR);
if(SUBRACE_SPELL_RESISTANCE_STACKS)
{
SR_int = SR_int + GetSpellResistance(oPC);
}
if(SR_int < 0)
{
SpellResistance = EffectSpellResistanceDecrease(abs(SR_int));
}
else
{
SpellResistance = EffectSpellResistanceIncrease(SR_int);
}
ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(SpellResistance), oPC);
SSE_MessageHandler(oPC, MESSAGE_SUBRACE_SPELL_RESISTANCE_APPLIED);
}
void ApplyTemporarySubraceStats(object oPC, string SubraceStorage, int iCurrentTime, int AreaUndAbove, int AreaIntExt, int AreaNatArt)
{
int iTime = GetSSEInt( SubraceStorage + "_" + SUBRACE_STAT_MODIFIERS);
iTime = iTime & ~FLAG12;
if(iTime > 0)
{
int CurrentState = 0;
if(AreaIntExt) CurrentState = CurrentState | FLAG4;
if(!AreaIntExt) CurrentState = CurrentState | FLAG5;
if(AreaUndAbove == AREA_UNDERGROUND) CurrentState = CurrentState | FLAG9;
if(AreaUndAbove == AREA_ABOVEGROUND) CurrentState = CurrentState | FLAG8;
if(AreaNatArt == AREA_NATURAL) CurrentState = CurrentState | FLAG7;
if(AreaNatArt == AREA_ARTIFICIAL) CurrentState = CurrentState | FLAG6;
SHA_ApplyTemporaryStats(oPC, SubraceStorage, iCurrentTime, iTime, CurrentState);
}
}
void TemporaryStatsVisualFX(object oPC)
{
effect eVis = EffectVisualEffect(VFX_IMP_IMPROVE_ABILITY_SCORE);
effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE);
effect Vfx = EffectLinkEffects(eVis, eDur);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, Vfx, oPC);
}
void SHA_ApplyTemporaryStats(object oPC, string SubraceStorage, int iCurrentTime, int iTime, int AreasReq/*int AreaUndAbove, int AreaIntExt, int AreaNatArt*/)
{
string SubraceStorage1 = SubraceStorage + IntToString(iCurrentTime);
int AreasCan = GetSSEInt( SubraceStorage1 + "_" + SUBRACE_STAT_MODIFIERS);
int CurrentStatus = GetLocalInt(oPC, SUBRACE_STATS_STATUS);
switch(iCurrentTime)
{
case TIME_DAY:
{
if(!(iTime & TIME_DAY) && !(iTime & TIME_NIGHT))
{
return;
}
if((CurrentStatus == TIME_SPECIAL_APPEARANCE_SUBRACE) || (CurrentStatus == TIME_SPECIAL_APPEARANCE_NORMAL))
{
return;
}
if((CurrentStatus == TIME_NIGHT) || ((CurrentStatus == TIME_DAY) && (~AreasCan & AreasReq)))
{
ClearSubraceTemporaryStats(oPC);
SSE_MessageHandler(oPC, MESSAGE_ABILITY_SCORES_REVERTED);
DeleteLocalInt(oPC, SUBRACE_STATS_STATUS);
}
if((iTime & TIME_DAY) && (AreasCan & AreasReq) && (CurrentStatus == TIME_DAY))
{
return;
}
break;
}
case TIME_NIGHT:
{
if(!(iTime & TIME_DAY) && !(iTime & TIME_NIGHT))
{
return;
}
if((CurrentStatus == TIME_SPECIAL_APPEARANCE_SUBRACE) || (CurrentStatus == TIME_SPECIAL_APPEARANCE_NORMAL))
{
return;
}
if((CurrentStatus == TIME_DAY) || ((CurrentStatus == TIME_NIGHT) && (~AreasCan & AreasReq)))
{
ClearSubraceTemporaryStats(oPC);
SSE_MessageHandler(oPC, MESSAGE_ABILITY_SCORES_REVERTED);
DeleteLocalInt(oPC, SUBRACE_STATS_STATUS);
}
if((iTime & TIME_NIGHT) && (AreasCan & AreasReq) && (CurrentStatus == TIME_NIGHT))
{
return;
}
break;
}
case TIME_SPECIAL_APPEARANCE_SUBRACE:
{
//appearance ability score takes priority...
//normal appearance ability score takes priority...
if((CurrentStatus == TIME_SPECIAL_APPEARANCE_NORMAL) || (CurrentStatus == TIME_DAY) || (CurrentStatus == TIME_NIGHT) || (~AreasCan & AreasReq))
{
ClearSubraceTemporaryStats(oPC);
SSE_MessageHandler(oPC, ((CurrentStatus & TIME_SPECIAL_APPEARANCE_NORMAL)?MESSAGE_ABILITY_SCORES_APPEARANCE_TRIGGERED_REVERTED:MESSAGE_ABILITY_SCORES_REVERTED));
DeleteLocalInt(oPC, SUBRACE_STATS_STATUS);
}
//appearance is not normal, area requirements are met, and status says the stats have been applied, then return;
CurrentStatus = GetLocalInt(oPC, SUBRACE_STATS_STATUS);
if((GetAppearanceType(oPC) != SHA_GetDefaultAppearanceType(oPC)) && (AreasReq & AreasCan) && (CurrentStatus == TIME_SPECIAL_APPEARANCE_SUBRACE))
{
return;
}
if(!(iTime & TIME_SPECIAL_APPEARANCE_SUBRACE))
{
return;
}
break;
}
case TIME_SPECIAL_APPEARANCE_NORMAL:
{
//normal appearance ability score takes priority...
if((CurrentStatus == TIME_SPECIAL_APPEARANCE_SUBRACE) || (CurrentStatus == TIME_DAY) || (CurrentStatus == TIME_NIGHT) || (~AreasCan & AreasReq))
{
ClearSubraceTemporaryStats(oPC);
SSE_MessageHandler(oPC, ((CurrentStatus == TIME_SPECIAL_APPEARANCE_SUBRACE)?MESSAGE_ABILITY_SCORES_APPEARANCE_TRIGGERED_REVERTED:MESSAGE_ABILITY_SCORES_REVERTED));
DeleteLocalInt(oPC, SUBRACE_STATS_STATUS);
}
if((GetAppearanceType(oPC) == SHA_GetDefaultAppearanceType(oPC)) && (AreasReq & AreasCan) && (CurrentStatus == iCurrentTime))
{
return;
}
if(!(iTime & TIME_SPECIAL_APPEARANCE_NORMAL))
{
return;
}
break;
}
}
if(!(iTime & iCurrentTime))
{
return;
}
if((~AreasCan & AreasReq))
{
return;
}
SetLocalInt(oPC, SUBRACE_STATS_STATUS, iCurrentTime);
int iType = GetSSEInt( SubraceStorage + IntToString(iCurrentTime) + "_" + SUBRACE_STAT_MODIFIER_TYPE);
SubraceStorage = SubraceStorage + IntToString(iCurrentTime);
if(GetIsResting(oPC))
{
AssignCommand(oPC, ClearAllActions(TRUE));
}
ClearSubraceTemporaryStats(oPC);
if(iType == SUBRACE_STAT_MODIFIER_TYPE_PERCENTAGE)
{
AssignCommand(oPC, ApplySubraceBonusStatsByPercentage(oPC, SubraceStorage));
}
else if(iType == SUBRACE_STAT_MODIFIER_TYPE_POINTS)
{
AssignCommand(oPC, ApplySubraceBonusStatsByPoints(oPC, SubraceStorage));
}
//STAT MODIFIER TYPE Unrecognised
else return;
DelayCommand(1.0, TemporaryStatsVisualFX(oPC));
DelayCommand(1.0, SSE_MessageHandler(oPC, MESSAGE_ABILITY_SCORES_CHANGED) );
}
void ClearSubraceEffects(object oPC)
{
effect eBad = GetFirstEffect(oPC);
while(GetIsEffectValid(eBad))
{
int iType = GetEffectType(eBad);
//Remove effect if it is a subracial effect
if(GetEffectCreator(eBad) == oStorer &&
( GetEffectSubType(eBad) == SUBTYPE_SUPERNATURAL) ||
( iType == EFFECT_TYPE_VISUALEFFECT ) )
{
if (iType == EFFECT_TYPE_ARCANE_SPELL_FAILURE ||
iType == EFFECT_TYPE_BLINDNESS ||
iType == EFFECT_TYPE_CHARMED ||
iType == EFFECT_TYPE_CONCEALMENT ||
iType == EFFECT_TYPE_CONFUSED ||
iType == EFFECT_TYPE_CUTSCENEGHOST ||
iType == EFFECT_TYPE_HASTE ||
iType == EFFECT_TYPE_IMMUNITY ||
iType == EFFECT_TYPE_IMPROVEDINVISIBILITY ||
iType == EFFECT_TYPE_INVISIBILITY ||
iType == EFFECT_TYPE_MISS_CHANCE ||
iType == EFFECT_TYPE_MOVEMENT_SPEED_DECREASE ||
iType == EFFECT_TYPE_MOVEMENT_SPEED_INCREASE ||
iType == EFFECT_TYPE_POLYMORPH ||
iType == EFFECT_TYPE_REGENERATE ||
iType == EFFECT_TYPE_SANCTUARY ||
iType == EFFECT_TYPE_SLOW ||
iType == EFFECT_TYPE_TEMPORARY_HITPOINTS ||
iType == EFFECT_TYPE_TRUESEEING ||
iType == EFFECT_TYPE_ULTRAVISION ||
iType == EFFECT_TYPE_VISUALEFFECT ||
iType == EFFECT_TYPE_DAMAGE_IMMUNITY_INCREASE ||
iType == EFFECT_TYPE_DAMAGE_IMMUNITY_DECREASE)
{
RemoveEffect(oPC, eBad);
}
}
eBad = GetNextEffect(oPC);
}
}
void ClearSubraceTemporaryStats(object oPC)
{
effect eBad = GetFirstEffect(oPC);
while(GetIsEffectValid(eBad))
{
int iType = GetEffectType(eBad);
if (iType == EFFECT_TYPE_ABILITY_DECREASE ||
iType == EFFECT_TYPE_ABILITY_INCREASE ||
iType == EFFECT_TYPE_AC_DECREASE ||
iType == EFFECT_TYPE_AC_INCREASE ||
iType == EFFECT_TYPE_ATTACK_INCREASE ||
iType == EFFECT_TYPE_ATTACK_DECREASE ||
iType == EFFECT_TYPE_SPELL_RESISTANCE_DECREASE ||
iType == EFFECT_TYPE_SPELL_RESISTANCE_INCREASE ||
iType == EFFECT_TYPE_SAVING_THROW_DECREASE)
{
//Remove effect if it is a subracial effect
if(GetEffectSubType(eBad) == SUBTYPE_SUPERNATURAL)
{
if(GetEffectCreator(eBad) == oPC)
{
RemoveEffect(oPC, eBad);
}
}
}
eBad = GetNextEffect(oPC);
}
}
void ApplySubraceBonusStatsByPoints(object oPC, string SubraceStorage)
{
int i=0;
for( ; i < 6 ; i++)
{
float statMod = GetLocalFloat(oStorer, SubraceStorage + "_" + GetSubraceStatStorageName(i, FALSE) );
if(statMod != 0.0)
{
ApplyStat_AbilityByPoints(i, statMod, oPC);
}
}
float ABMod = GetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_STAT_AB_MODIFIER);
float ACMod = GetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_STAT_AC_MODIFIER);
if(ABMod != 0.0)
{
ApplyAttackBonusByPoints(ABMod, oPC);
}
if(ACMod != 0.0)
{
ApplyArmourClassBonusByPoints(ACMod, oPC);
}
}
void ApplyStat_AbilityByPoints(int AbilityToMod, float points, object oPC)
{
int StatIncrease = FloatToInt(points);
effect StatEffect;
if(StatIncrease > 0)
{
StatEffect = EffectAbilityIncrease(AbilityToMod, StatIncrease);
}
else if(StatIncrease < 0)
{
int StatIncrease1 = abs(StatIncrease);
StatEffect = EffectAbilityDecrease(AbilityToMod, StatIncrease1);
}
ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(StatEffect), oPC);
}
void ApplyAttackBonusByPoints(float points, object oPC)
{
int ABChange = FloatToInt(points);
effect StatEffect;
effect StatEffect1;
if(ABChange > 0)
{
StatEffect = EffectAttackIncrease(ABChange, ATTACK_BONUS_ONHAND);
StatEffect1 = EffectAttackIncrease(ABChange, ATTACK_BONUS_OFFHAND);
}
else if(ABChange < 0)
{
int ABChange1 = abs(ABChange);
StatEffect = EffectAttackDecrease(ABChange1, ATTACK_BONUS_ONHAND);
StatEffect1 = EffectAttackDecrease(ABChange1, ATTACK_BONUS_OFFHAND);
}
ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(StatEffect), oPC);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(StatEffect1), oPC);
}
void ApplyArmourClassBonusByPoints(float points, object oPC)
{
int ACChange = FloatToInt(points);
effect StatEffect;
if(ACChange > 0)
{
StatEffect = EffectACIncrease(ACChange, AC_NATURAL_BONUS);
}
else if(ACChange < 0)
{
int ACChange1 = abs(ACChange);
StatEffect = EffectACDecrease(ACChange1, AC_NATURAL_BONUS);
}
ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(StatEffect), oPC);
}
void ApplySubraceBonusStatsByPercentage(object oPC, string SubraceStorage)
{
int i=0;
for( ; i < 6 ; i++)
{
float statMod = GetLocalFloat(oStorer, SubraceStorage + "_" + GetSubraceStatStorageName(i, FALSE) );
if(statMod != 0.0)
{
ApplyStat_AbilityByPercentage(i, statMod, oPC);
}
}
float ABMod = GetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_STAT_AB_MODIFIER);
float ACMod = GetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_STAT_AC_MODIFIER);
if(ABMod != 0.0)
{
ApplyAttackBonusByPercentage(ABMod, oPC);
}
if(ACMod != 0.0)
{
ApplyArmourClassBonusByPercentage(ACMod, oPC);
}
}
void ApplyStat_AbilityByPercentage(int AbilityToMod, float percentage, object oPC)
{
int currentStat = GetAbilityScore(oPC, AbilityToMod);
float cStat = IntToFloat(currentStat);
float Stat = cStat*percentage;
int newStat = FloatToInt(Stat);
effect StatEffect;
if(newStat > 0)
{
StatEffect = EffectAbilityIncrease(AbilityToMod, newStat);
}
else if(newStat < 0)
{
int newStat1 = abs(newStat);
StatEffect = EffectAbilityDecrease(AbilityToMod, newStat1);
}
ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(StatEffect), oPC);
}
void ApplyAttackBonusByPercentage(float percentage, object oPC)
{
float currentAB = IntToFloat(GetBaseAttackBonus(oPC));
int Neg = FALSE;
int Neg2 = FALSE;
if(currentAB < 0.0 ) { Neg = TRUE; }
if(percentage < 0.0 ) { Neg2 = TRUE; }
int newAB = FloatToInt(currentAB*percentage);
if(Neg && Neg2 ) { newAB = -newAB; }
effect StatEffect;
effect StatEffect1;
if(newAB > 0)
{
StatEffect = EffectAttackIncrease(newAB, ATTACK_BONUS_ONHAND);
StatEffect1 = EffectAttackIncrease(newAB, ATTACK_BONUS_OFFHAND);
}
else if(newAB < 0)
{
int newAB1 = abs(newAB);
StatEffect = EffectAttackDecrease(newAB1, ATTACK_BONUS_ONHAND);
StatEffect1 = EffectAttackDecrease(newAB1, ATTACK_BONUS_OFFHAND);
}
ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(StatEffect), oPC);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(StatEffect1), oPC);
}
void ApplyArmourClassBonusByPercentage(float percentage, object oPC)
{
float currentAC = IntToFloat(GetAC(oPC));
int newAC = FloatToInt(currentAC*percentage);
effect StatEffect;
if(newAC > 0)
{
StatEffect = EffectACIncrease(newAC, AC_NATURAL_BONUS, AC_VS_DAMAGE_TYPE_ALL);
}
else if(newAC < 0)
{
int newAC1 = abs(newAC);
StatEffect = EffectACDecrease(newAC1, AC_NATURAL_BONUS, AC_VS_DAMAGE_TYPE_ALL);
}
ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(StatEffect), oPC);
}
void SHA_SubraceForceUnequipItem(object oItem)
{
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectCutsceneImmobilize(), OBJECT_SELF, 0.1);
ClearAllActions(TRUE);
ActionUnequipItem(oItem);
ActionDoCommand(SetCommandable(TRUE));
SetCommandable(FALSE);
}
void SHA_SubraceForceEquipItem(object oItem, int InvoSlot)
{
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectCutsceneImmobilize(), OBJECT_SELF, 0.1);
ClearAllActions(TRUE);
ActionEquipItem(oItem, InvoSlot);
ActionDoCommand(SetCommandable(TRUE));
SetCommandable(FALSE);
}
void CheckCanUseItem(object oItem, object oPC, int iType = 1)
{
int ID = GetPlayerSubraceID(oPC);
if(!ID || !GetIsObjectValid(oItem))
{ return; }
//ingore creature items.
switch(GetBaseItemType(oItem))
{
case BASE_ITEM_CPIERCWEAPON:
case BASE_ITEM_CSLASHWEAPON:
case BASE_ITEM_CSLSHPRCWEAP:
case BASE_ITEM_CBLUDGWEAPON:
case BASE_ITEM_CREATUREITEM: return;
}
string SubraceStorage = GetSubraceStorageLocationByID(ID) + "_" + SUBRACE_ITEM_RESTRICTION + "_";
int Restrictions;
int Time = SHA_GetCurrentTime();
if(SHA_GetDefaultAppearanceType(oPC) == GetAppearanceType(oPC))
{
//Normal form
Restrictions = GetSSEInt( SubraceStorage + IntToString(TIME_SPECIAL_APPEARANCE_NORMAL) );
}
else
{
//Special form
Restrictions = GetSSEInt( SubraceStorage + IntToString(TIME_SPECIAL_APPEARANCE_SUBRACE) );
}
//No Special Restrictions based on appearance, try loading a time-based one!
if(!Restrictions)
{
Restrictions = GetSSEInt( SubraceStorage + IntToString(Time) );
}
//If no restrictions at all for the current time and form, Restrictions will be FALSE
if(Restrictions)
{
if(SHA_TestItemReq(GetItemType(oItem), Restrictions))
{
string sMsg;
switch(iType)
{
case 1: sMsg = "weapon"; break;
case 2: sMsg = "armor (or shield)"; break;
case 3: sMsg = "jewlery (or misc item)"; break;
default: sMsg = "item"; break;
}
SSE_MessageHandler(oPC, MESSAGE_SUBRACE_CANNOT_EQUIP_ITEM, sMsg);
DelayCommand(0.3, AssignCommand(oPC, SHA_SubraceForceUnequipItem(oItem)));
}
}
}
void SubraceOnPlayerEquipItem()
{
object oItem = GetPCItemLastEquipped();
object oPC = GetPCItemLastEquippedBy();
if(!GetPlayerSubraceID(oPC) || GetIsSSEDisabled()) return;
int iType = 1;
switch(GetBaseItemType(oItem))
{
case BASE_ITEM_ARMOR:
case BASE_ITEM_HELMET:
case BASE_ITEM_LARGESHIELD:
case BASE_ITEM_SMALLSHIELD:
case BASE_ITEM_TOWERSHIELD: iType = 2; break;
case BASE_ITEM_RING:
case BASE_ITEM_AMULET:
case BASE_ITEM_CLOAK:
case BASE_ITEM_GLOVES:
case BASE_ITEM_BRACER: iType = 3; break;
}
CheckCanUseItem(oItem, oPC, iType);
}
void CheckIfCanUseEquipedWeapon(object oPC)
{
if(!GetPlayerSubraceID(oPC)) return;
object Wep1 = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC);
object Wep2 = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC);
CheckCanUseItem (Wep1, oPC, 1);
DelayCommand(3.0, CheckCanUseItem (Wep2, oPC, 1));
}
void CheckIfCanUseEquippedArmor(object oPC)
{
if(!GetPlayerSubraceID(oPC))
{ return; }
object oItem = GetItemInSlot(INVENTORY_SLOT_CHEST, oPC);
CheckCanUseItem(oItem, oPC, 2);
}
string GetSubraceNameByID(int ID, int Lowercase=FALSE)
{
string Name=GetLocalString(oStorer, MODULE_SUBRACE_NUMBER + IntToString(ID) );
return Lowercase?GetStringLowerCase(Name):Name;
}
string GetSubraceNameByAlias(string Alias, int Lowercase=FALSE)
{
//Aliases have same ID as the Subrace, however only the base name
// is recorded at the "Subrace-Index"
return GetSubraceNameByID(GetSubraceID(Alias), Lowercase );
}
// 3.0.6.5 moons fix
void InitiateSubraceChecking(object oPC)
{
string subraceAlias = GetStringLowerCase(GetSubRace(oPC));
string subraceCased = GetSubraceNameByAlias(subraceAlias);
string subrace = GetStringLowerCase(subraceCased);
//3.0.6.5 - added default race changes
if (USE_SSE_DEFAULT_RACES)
{
if(subrace == "")
{
CheckAndApplyDefaultSubrace(oPC);
subraceAlias = GetStringLowerCase(GetSubRace(oPC));
subrace = GetSubraceNameByAlias(subraceAlias);
}
}
if(subrace != "")
{
//3.0.6.9 fix
int check1 = GetSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + "_" + subraceCased, oPC);
if(check1 != SUBRACE_UNINITIALIZED)
{SetSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + "_" + subrace, check1, oPC);
//3.0.6.7 fix
if(check1 == SUBRACE_UNINITIALIZED)
{
SetSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + "_" + subrace, check1, oPC);
DeleteSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + "_" + subraceCased, oPC);
}
}
if(check1 == SUBRACE_UNINITIALIZED)
{
int check2 = CheckIfPCMeetsAnySubraceCriteria(oPC);
if(check2 == SUBRACE_UNRECOGNISED)
{
return;
}
else if(!check2)
{
SetSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + "_" + subrace, SUBRACE_REJECTED, oPC);
return;
}
else if(check2)
{
SetSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + "_" + subrace, SUBRACE_ACCEPTED, oPC);
}
}
else if(check1 == SUBRACE_ACCEPTED)
{
}
else if(check1 == SUBRACE_REJECTED)
{
//SUBRACE was rejected previously.
return;
}
if(SEARCH_AND_DESTROY_SKINS_IN_INVENTORY)
{
SearchAndDestroySkinsAndClaws(oPC);
}
DelayCommand(1.0, LoadSubraceInfoOnPC(oPC, subraceAlias));
DelayCommand(22.0, Subrace_MoveToStartLocation(oPC, subraceAlias));
}
}
void Subrace_MoveToStartLocation(object oPC, string subrace = "")
{
// 3.0.6.5
if (subrace == "")
{
string subrace = GetSubraceNameByAlias(GetSubRace(oPC));
}
string SubraceStorage = GetSubraceStorageLocation(subrace);
string WPTag = GetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_START_LOCATION);
object oWP = GetWaypointByTag(WPTag);
if( GetIsObjectValid(oWP) )
{
DelayCommand(0.5, AssignCommand(oPC, JumpToLocation(GetLocation(oWP))));
DelayCommand(0.5, SSE_MessageHandler(oPC, MESSAGE_SUBRACE_MOVE_TO_START_LOCATION, CapitalizeString(subrace)) );
}
}
//3.0.6.4
//3.0.6.5 fix - string subrace removed
void Subrace_MoveToDeathLocation(object oPC)
{
string subraceAlias = GetSubRace(oPC);
string subrace = GetSubraceNameByAlias(subraceAlias, TRUE);
string SubraceStorage = GetSubraceStorageLocation(subrace);
string WPTag = GetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_DEATH_LOCATION);
object oWP = GetWaypointByTag(WPTag);
object oDefaultWP = GetWaypointByTag(SUBRACE_DEATH_DEFAULT);
if( GetIsObjectValid(oWP) )
{
DelayCommand(0.5, AssignCommand(oPC, JumpToLocation(GetLocation(oWP))));
}
else
{
//3.0.6.5 fix - defaults to GetStartingLocation()
if( GetIsObjectValid(oWP) )
{
DelayCommand(0.5, AssignCommand(oPC, JumpToLocation(GetLocation(oDefaultWP))));
}
else
{
DelayCommand(0.5, AssignCommand(oPC, JumpToLocation(GetStartingLocation())));
}
}
}
void ChangeSubraceFactions(object oPC, string subrace)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
int Count = GetSSEInt( SubraceStorage + "_" + SUBRACE_FACTION_COUNT);
if(Count)
{
float fDelay;
while(Count != 0)
{
fDelay += 0.10;
string FactionCreatureTag = GetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_FACTION_CREATURE + "_" + IntToString(Count));
int Reputation = GetSSEInt( SubraceStorage + "_" + SUBRACE_FACTION_REPUTATION + "_" + IntToString(Count));
DelayCommand(fDelay, Subrace_FactionAdjustment(oPC, FactionCreatureTag, Reputation));
Count--;
}
SHA_SendSubraceMessageToPC(oPC, SSE_GetStandardMessage(MESSAGE_SUBRACE_FACTION_ADJUSTED), FALSE);
}
}
void Subrace_FactionAdjustment(object oPC, string FactionTag, int Adjustment)
{
object Faction = GetObjectByTag(FactionTag);
if( GetIsObjectValid(Faction) )
{
ClearPersonalReputation(oPC, Faction);
ClearPersonalReputation(Faction, oPC);
//Make friendly first..
AdjustReputation(oPC, Faction, 100);
//Now adjust
AdjustReputation(oPC, Faction, Adjustment);
}
}
void CheckAndSwitchSubrace(object oPC)
{
string subrace = GetStringLowerCase(GetSubRace(oPC));
// 3.0.6.5
if(subrace == "")
{
if (USE_SSE_DEFAULT_RACES)
{
CheckAndApplyDefaultSubrace(oPC);
subrace = GetStringLowerCase(GetSubRace(oPC));
}
else { return; }
}
string SubraceStorage = GetSubraceStorageLocation(subrace);
int Level = GetPlayerLevel(oPC);
string switchSubraceNames = GetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_SWITCH_NAME + IntToString(Level));
if(switchSubraceNames != "")
{
while(switchSubraceNames != "")
{
int iPos = FindSubString(switchSubraceNames, "_");
string sSubrace;
if(iPos != -1)
{
sSubrace = GetStringLeft(switchSubraceNames, iPos);
}
else
{
sSubrace = switchSubraceNames;
}
switchSubraceNames = GetStringRight(switchSubraceNames, GetStringLength(switchSubraceNames) - iPos - 1);
string CurrentSubrace = GetSubRace(oPC);
string NewSubrace = sSubrace;
//SetSubRace(oPC, NewSubrace);
//subrace = GetStringLowerCase(GetSubRace(oPC));
SSE_MessageHandler(oPC, MESSAGE_SUBRACE_SWITCH_CHECKING_REQUIREMENTS, NewSubrace);
int check = FALSE;
int NeedToMeetRequirements = GetSSEInt( SubraceStorage + "_" + SUBRACE_SWITCH_MUST_MEET_REQUIREMENTS + IntToString(Level));
//only check restrictions if need be.
if(NeedToMeetRequirements)
{
check = CheckIfPCMeetsAnySubraceCriteria(oPC);
}
if(!check)
{
subrace = GetStringLowerCase(NewSubrace);
SetSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + "_" + subrace, SUBRACE_ACCEPTED, oPC);
DeleteSubraceInfoOnPC(oPC);
DelayCommand(4.2, SSE_MessageHandler(oPC, MESSAGE_SUBRACE_SWITCHING, NewSubrace + "..."));
DelayCommand(4.3, SetSubRace(oPC, NewSubrace));
DelayCommand(5.1, LoadSubraceInfoOnPC(oPC, NewSubrace));
DelayCommand(15.0, CheckIfCanUseEquipedWeapon(oPC));
DelayCommand(18.5, CheckIfCanUseEquippedArmor(oPC));
DelayCommand(21.5, SSE_MessageHandler(oPC, MESSAGE_SUBRACE_SWITCHED));
return;
}
}
}
}
void ModifyAttachments(object oPC, string SubraceStorage, int Level)
{
string script = "";
string SubraceStorage1 = SubraceStorage + "_" + IntToString(Level);
if(GetSSEInt( SubraceStorage1 + "_" + SUBRACE_ATTACHMENT_FLAGS) )
{
int Gender = GetGender(oPC);
int Wings = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + SUBRACE_ATTACHMENT_FLAGS, (Gender==GENDER_MALE?SUBRACE_ATTACHMENT_FLAGS_WINGS_MALE:SUBRACE_ATTACHMENT_FLAGS_WINGS_FEMALE ) );
int Tail = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + SUBRACE_ATTACHMENT_FLAGS, (Gender==GENDER_MALE?SUBRACE_ATTACHMENT_FLAGS_TAIL_MALE:SUBRACE_ATTACHMENT_FLAGS_TAIL_FEMALE ) );
if(Wings) { SetCreatureWingType(Wings, oPC); SSE_MessageHandler(oPC, MESSAGE_SUBRACE_NEW_WINGS_GAINED);}
if(Tail) { SetCreatureTailType(Tail, oPC); SSE_MessageHandler(oPC, MESSAGE_SUBRACE_NEW_TAIL_GAINED); }
}
}
void ModifyPortrait(object oPC, string SubraceStorage, int Level)
{
string SubraceStorage1 = SubraceStorage + "_" + IntToString(Level);
string Gender = (GetGender(oPC)==GENDER_MALE?SUBRACE_PORTRAIT_MALE:SUBRACE_PORTRAIT_FEMALE);
string Portrait = GetLocalString(oStorer, SubraceStorage1 + "_" + SUBRACE_PORTRAIT + "_" + Gender);
if(Portrait != "")
{
SetPortraitResRef(oPC, Portrait);
SSE_MessageHandler(oPC, MESSAGE_SUBRACE_NEW_PORTRAIT_GAINED);
}
}
void ChangeMiscellaneousSubraceStuff(object oPC, int Level)
{
string SubraceStorage = GetSubraceStorageLocationByID(GetPlayerSubraceID(oPC));
ModifyAttachments(oPC, SubraceStorage, Level);
ModifyPortrait(oPC, SubraceStorage, Level);
}
void SubraceOnPlayerLevelUp()
{
object oPC = GetPCLevellingUp();
if(!GetPlayerSubraceID(oPC))
{
return;
}
if(GetIsSSEDisabled())
{
SSE_MessageHandler(oPC, MESSAGE_SUBRACE_SSE_IS_SHUTDOWN);
return;
}
int Level = GetPlayerLevel(oPC);
ReapplySubraceAbilities(oPC);
DelayCommand(2.5, ChangeMiscellaneousSubraceStuff(oPC, Level));
DelayCommand(2.0, CheckAndGiveSubraceItems(oPC));
int NeedsToRelog = CheckForLetoReLog(oPC, Level);
if(NeedsToRelog)
{
if(!LETO_ACTIVATE_PORTAL)
{
DelayCommand(5.0, PopUpDeathGUIPanel(oPC, FALSE, FALSE, 0, SUBRACE_ENGINE + SSE_GetStandardMessage(MESSAGE_LETO_PLEASE_RELOG)));
if(LETO_AUTOMATICALLY_BOOT)
{
DelayCommand(5.2, SSE_MessageHandler(oPC, MESSAGE_LETO_AUTOBOOT, IntToString(LETO_AUTOMATIC_BOOT_DELAY)));
DelayCommand(5.2 + IntToFloat(LETO_AUTOMATIC_BOOT_DELAY), DelayBoot(oPC));
}
}
else
{
if(!LETO_PORTAL_KEEP_CHARACTER_IN_THE_SAME_PLACE)
{
DelayCommand(5.2, SSE_MessageHandler(oPC, MESSAGE_LETO_AUTOPORTAL, IntToString(LETO_AUTOMATIC_PORTAL_DELAY)));
DelayCommand(5.2 + IntToFloat(LETO_AUTOMATIC_PORTAL_DELAY), ActivatePortal(oPC, LETO_PORTAL_IP_ADDRESS, LETO_PORTAL_SERVER_PASSWORD, LETO_PORTAL_WAYPOINT, TRUE));
}
else
{
int RandomNumber = d100(1);
string sWPTag = "WP_SUBRACE_P" + IntToString(RandomNumber);
object oWaypoint = CreateObject(OBJECT_TYPE_WAYPOINT, "nw_waypoint001", GetLocation(oPC), FALSE, sWPTag);
DelayCommand(5.2, SSE_MessageHandler(oPC, MESSAGE_LETO_DONT_PANIC_JUSTPORTING));
DelayCommand(5.2 + IntToFloat(LETO_AUTOMATIC_PORTAL_DELAY), ActivatePortal(oPC, LETO_PORTAL_IP_ADDRESS, LETO_PORTAL_SERVER_PASSWORD, sWPTag, TRUE));
DelayCommand(15.0 + IntToFloat(LETO_AUTOMATIC_PORTAL_DELAY), DestroyObject(oWaypoint, 0.1));
}
}
DelayCommand(5.0, SetSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + LETO_CHANGES_MADE_FOR_THIS_LEVEL + "_" + GetStringLowerCase(GetSubRace(oPC)), Level, oPC));
}
DelayCommand(5.0, CheckAndSwitchSubrace(oPC));
}
string LetoSubraceModifications(object oPC, string SubraceStorage, int Level, int LastLetoLevelChanges)
{
string ScriptForLeto = "";
LastLetoLevelChanges++;
while(LastLetoLevelChanges <= Level)
{
ScriptForLeto += CheckAndModifyBaseStats(oPC, SubraceStorage, LastLetoLevelChanges);
ScriptForLeto += CheckAndModifyFeats(oPC, SubraceStorage, LastLetoLevelChanges);
ScriptForLeto += CheckAndModifySoundSet(oPC, SubraceStorage, LastLetoLevelChanges);
ScriptForLeto += CheckAndModifySkills(oPC, SubraceStorage, LastLetoLevelChanges);
//3.0.6.6
// ScriptForLeto += CheckAndModifyColors(oPC, SubraceStorage, LastLetoLevelChanges);
LastLetoLevelChanges++;
}
return ScriptForLeto;
}
int CheckForLetoReLog(object oPC, int Level)
{
if(!ENABLE_LETO)
{ return FALSE; }
//Need lowercase sub-race name for database.
string subrace = GetStringLowerCase(GetSubRace(oPC));
string SubraceStorage = GetSubraceStorageLocation(GetSubRace(oPC));
int LetoChanges = GetSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + LETO_CHANGES_MADE_FOR_THIS_LEVEL + "_" + subrace, oPC);
if(LetoChanges >= Level)
{ return FALSE; }
int NeedsToRelog = FALSE;
string LetoScriptToFile = LetoSubraceModifications(oPC, SubraceStorage, Level, LetoChanges);
if(LetoScriptToFile != "")
{
NeedsToRelog = TRUE;
SetLocalString(oPC, "LETO_SCRIPT_TO_FILE", LetoScriptToFile);
}
SetLocalInt(oPC, "SUBRACE_NEEDS_TO_RELOG", NeedsToRelog);
return NeedsToRelog;
}
void SubraceOnClientLeave()
{
object oPC = GetExitingObject();
int LetoChanges = GetLocalInt(oPC, "SUBRACE_NEEDS_TO_RELOG");
//Is Leto Enabled? Is there any changes to be made?
//No ID check needed, since SSE do not make Leto requests for sub-raceless players.
if(!ENABLE_LETO && !LetoChanges)
{ return; }
if(LetoChanges)
{
int Level = GetPlayerLevel(oPC);
string SubraceStorage = GetSubraceStorageLocationByID(GetPlayerSubraceID(oPC));
string BicFile = LETO_GetBicPath(oPC);
string ScriptForLeto = GetLocalString(oPC, "LETO_SCRIPT_TO_FILE");
WriteTimestampedLogEntry("*Subrace Engine LETOScript call for " + GetName(oPC) + " | " + GetLocalString(oPC, "SUBR_PlayerName") + " | " + BicFile + "* ");
string LetoError = LetoScript("%char= q!"+BicFile+"!; "+ScriptForLeto+"%char = '>'; close %char; ");
if(LetoError != "")
{
WriteTimestampedLogEntry("*Subrace Engine LETOScript Error: " + LetoError + "*");
}
DeleteLocalString(oPC, "LETO_SCRIPT_TO_FILE");
DeleteLocalInt(oPC, "SUBRACE_NEEDS_TO_RELOG");
}
}
string CheckAndModifyBaseStats(object oPC, string SubraceStorage, int Level)
{
string script = "";
string SubraceStorage1 = SubraceStorage + "_" + IntToString(Level);
int HasBMods = GetSSEInt( SubraceStorage1 + "_" + SUBRACE_HAS_BASE_STAT_MODIFIERS);
if(HasBMods)
{
int StrengthModifier = GetSSEInt( SubraceStorage1 + "_" + SUBRACE_BASE_STAT_STR_MODIFIER);
int DexterityModifier = GetSSEInt( SubraceStorage1 + "_" + SUBRACE_BASE_STAT_DEX_MODIFIER);
int ConstitutionModifier = GetSSEInt( SubraceStorage1 + "_" + SUBRACE_BASE_STAT_CON_MODIFIER);
int IntelligenceModifier = GetSSEInt( SubraceStorage1 + "_" + SUBRACE_BASE_STAT_INT_MODIFIER);
int WisdomModifier = GetSSEInt( SubraceStorage1 + "_" + SUBRACE_BASE_STAT_WIS_MODIFIER);
int CharismaModifier = GetSSEInt( SubraceStorage1 + "_" + SUBRACE_BASE_STAT_CHA_MODIFIER);
int SpdModifier = GetSSEInt( SubraceStorage1 + "_" + SUBRACE_BASE_STAT_SPD_MODIFIER);
int Set = GetSSEInt( SubraceStorage1 + "_" + SUBRACE_BASE_STAT_MODIFIERS_REPLACE);
if(StrengthModifier)
script += LETO_ModifyProperty("Str", StrengthModifier, Set);
if(DexterityModifier)
script += LETO_ModifyProperty("Dex", DexterityModifier, Set);
if(ConstitutionModifier)
script += LETO_ModifyProperty("Con", ConstitutionModifier, Set);
if(WisdomModifier)
script += LETO_ModifyProperty("Wis", WisdomModifier, Set);
if(IntelligenceModifier)
script += LETO_ModifyProperty("Int", IntelligenceModifier, Set);
if(CharismaModifier)
script += LETO_ModifyProperty("Cha", CharismaModifier, Set);
script += LETO_SetMovementSpeed(SpdModifier);
}
return script;
}
string CheckAndModifyFeats(object oPC, string SubraceStorage, int Level)
{
string script = "";
string SubraceStorage1 = SubraceStorage + "_" + IntToString(Level);
int FeatCount = GetSSEInt( SubraceStorage1 + "_" + SUBRACE_BONUS_FEAT_COUNT);
if(FeatCount > 0)
{
while(FeatCount)
{
int Feat = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + IntToString(FeatCount) + "_" + SUBRACE_BONUS_FEAT_FLAGS, SUBRACE_BONUS_FEAT_FLAG);
int Remove = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + IntToString(FeatCount) + "_" + SUBRACE_BONUS_FEAT_FLAGS, SUBRACE_BONUS_FEAT_REMOVE_FLAG);
FeatCount--;
script += LETO_ModifyFeat(Feat, Remove);
}
}
return script;
}
string CheckAndModifySkills(object oPC, string SubraceStorage, int Level)
{
string script = "";
string SubraceStorage1 = SubraceStorage + "_" + IntToString(Level);
int SkillCount = GetSSEInt( SubraceStorage1 + "_" + SUBRACE_BONUS_SKILL_COUNT);
if(SkillCount > 0)
{
while(SkillCount)
{
int Skill = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + IntToString(SkillCount) + "_" + SUBRACE_BONUS_SKILL_FLAGS, SUBRACE_BONUS_SKILL_FLAG);
int Remove = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + IntToString(SkillCount) + "_" + SUBRACE_BONUS_SKILL_FLAGS, SUBRACE_BONUS_SKILL_REMOVE_FLAG);
int Mod = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + IntToString(SkillCount) + "_" + SUBRACE_BONUS_SKILL_FLAGS, SUBRACE_BONUS_SKILL_MODIFIER_FLAG);
SkillCount--;
script += LETO_ModifySkill(Skill, Mod, Remove);
}
}
return script;
}
string CheckAndModifySoundSet(object oPC, string SubraceStorage, int Level)
{
string SubraceStorage1 = SubraceStorage + "_" + IntToString(Level);
int Gender = (GetGender(oPC)==GENDER_MALE)?SUBRACE_SOUNDSET_MALE_FLAG:SUBRACE_SOUNDSET_FEMALE_FLAG;
int SoundSet = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + SUBRACE_SOUNDSET_FLAGS, Gender);
if(SoundSet)
{
return LETO_SetSoundSet(SoundSet);
}
return "";
}
void SubraceOnPlayerRespawn()
{
object oPC = GetLastRespawnButtonPresser();
ReapplySubraceAbilities(oPC);
DelayCommand(2.0, ChangeSubraceFactions(oPC, GetStringLowerCase(GetSubRace(oPC))));
}
void ReapplySubraceAbilities(object oPC)
{
int ID = GetPlayerSubraceID(oPC);
if(!ID)
{ return; }
if(GetIsSSEDisabled())
{
SSE_MessageHandler(oPC, MESSAGE_SUBRACE_SSE_IS_SHUTDOWN);
return;
}
DeleteLocalInt(oPC, SUBRACE_INFO_LOADED_ON_PC);
DeleteLocalInt(oPC, SUBRACE_IN_SPELL_DARKNESS);
string SubraceStorage = GetSubraceStorageLocationByID(ID);
int IsLightSens = GetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_LIGHT_SENSITIVE, SUBRACE_BASE_INFORMATION_FLAGS);
int IsUndergSens = GetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_UNDERGROUND_SENSITIVE, SUBRACE_BASE_INFORMATION_FLAGS);
if(IsLightSens)
{
DeleteLocalInt(oPC,"SB_LGHT_DMGED");
}
if(IsUndergSens)
{
DeleteLocalInt(oPC,"SB_DARK_DMGED");
}
ApplyPermanentSubraceSpellResistance(ID, oPC);
int HasDiffStats = GetSSEInt( SubraceStorage + "_" + SUBRACE_STAT_MODIFIERS);
if(HasDiffStats > 0)
{
DeleteLocalInt(oPC, SUBRACE_STATS_STATUS);
ClearSubraceTemporaryStats(oPC);
}
ClearSubraceEffects(oPC);
int iTime = SHA_GetCurrentTime();
DelayCommand(1.5, ApplyTemporarySubraceAppearance(SubraceStorage, oPC, iTime ));
DelayCommand(2.0, ApplyPermanentSubraceAppearance(ID, oPC));
// 3.0.6.6
DelayCommand(2.5, ApplySubraceColors(oPC));
DelayCommand(3.0, ApplySubraceEyeColors(oPC));
// 3.0.6.9
DelayCommand(3.5, ApplySubraceHead(oPC));
DelayCommand(4.0, SearchAndDestroySkinsAndClaws(oPC));
DelayCommand(4.5, ApplySubraceEffect(oPC, SubraceStorage, iTime));
DelayCommand(5.0, EquipTemporarySubraceSkin(SubraceStorage, oPC, iTime));
DelayCommand(6.0, EquipTemporarySubraceClaw(SubraceStorage, oPC, iTime));
DelayCommand(6.1, SetLocalInt(oPC, SUBRACE_INFO_LOADED_ON_PC, TRUE));
}
int SHA_GetCurrentTime()
{
if(GetIsNight() || GetIsDusk())
{
return TIME_NIGHT;
}
return TIME_DAY;
}
void SwapAppearance(object oPC, string subrace)
{
string SubraceStorage = GetSubraceStorageLocation(subrace);
int Level = GetPlayerLevel(oPC);
while(Level)
{
string SubraceStorage1 = SubraceStorage + "_" + IntToString(Level);
int iTime = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + APPEARANCE_CHANGE, TIME_FLAGS);
if(iTime)
{
if(SHA_GetDefaultAppearanceType(oPC) == GetAppearanceType(oPC))
{
ChangePCAppearance(oPC, SubraceStorage1);
object oArea = GetArea(oPC);
int AreaLocation = GetIsAreaAboveGround(oArea);
int Interior = GetIsAreaInterior(oArea);
int Natural = GetIsAreaNatural(oArea);
ApplyTemporarySubraceStats(oPC, SubraceStorage, TIME_SPECIAL_APPEARANCE_SUBRACE, AreaLocation, Interior, Natural);
DelayCommand(3.0, CheckIfCanUseEquipedWeapon(oPC));
DelayCommand(6.0, CheckIfCanUseEquippedArmor(oPC));
}
else
{
ChangeToPCDefaultAppearance(oPC);
object oArea = GetArea(oPC);
int AreaLocation = GetIsAreaAboveGround(oArea);
int Interior = GetIsAreaInterior(oArea);
int Natural = GetIsAreaNatural(oArea);
ApplyTemporarySubraceStats(oPC, SubraceStorage, TIME_SPECIAL_APPEARANCE_NORMAL, AreaLocation, Interior, Natural);
DelayCommand(3.0, CheckIfCanUseEquipedWeapon(oPC));
DelayCommand(6.0, CheckIfCanUseEquippedArmor(oPC));
}
return;
}
Level--;
}
}
void SubraceCheckItemActivated(object oPC, string sTag)
{
string subrace = GetStringLowerCase(GetSubRace(oPC));
if(subrace == "")
{ return; }
if(subrace == sTag)
{
SwapAppearance(oPC, subrace);
}
}
void SubraceOnItemActivated()
{
object oPC = GetItemActivator();
object oItem = GetItemActivated();
object oTarget = GetItemActivatedTarget();
string sTag = GetStringLowerCase(GetTag(oItem));
//Will still recognise the old tag!
if(sTag == "swand" || sTag == "_dm_subrace_wand")
{
//Moved all of this code into the Subrace Wand's swand_StartConversation() call (see sw_main_inc or sw_proto_inc)
AssignCommand(oPC, ActionStartConversation(oPC, "swand", FALSE, FALSE));
}
if(GetIsSSEDisabled())
{
return;
}
int iAbility = StringToInt(sTag);
if (iAbility > 0 )
{
SubraceAbility(oPC,iAbility,oTarget);
}
else
if(sTag == "_potion_blood")
{
effect eDmg;
effect eVisual = EffectVisualEffect(VFX_IMP_HARM);
if(Subrace_GetIsUndead(oPC))
{
eDmg = EffectHeal(GetMaxHitPoints(oPC));
}
else
{
int iDmg = GetCurrentHitPoints(oPC) - d4();
if(iDmg < 1)
{
iDmg = 1;
}
eDmg = EffectDamage(iDmg, DAMAGE_TYPE_NEGATIVE, DAMAGE_POWER_ENERGY);
}
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eDmg, oPC);
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVisual, GetLocation(oPC));
}
else if(sTag == "dimension_door")
{
location lTarget = GetItemActivatedTargetLocation();
if (GetAreaFromLocation(lTarget)==OBJECT_INVALID) return;
AssignCommand(oPC, ClearAllActions());
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD), oPC);
DelayCommand(1.0, AssignCommand(oPC, ActionJumpToLocation(lTarget)));
DelayCommand(1.1, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD), oPC));
}
else if(sTag == "fly_to")
{
object oArea = GetArea(oPC);
if (GetLocalInt(oArea, "NOFLY")==1)
{
FloatingTextStringOnCreature("<cڥ >You are unable to fly in this location!!</c>", GetItemActivator());
return;
}
/*
location lTarget = GetItemActivatedTargetLocation();
if (GetAreaFromLocation(lTarget)==OBJECT_INVALID) return;
AssignCommand(oPC, ClearAllActions());
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD), oPC);
DelayCommand(1.0, AssignCommand(oPC, ActionJumpToLocation(lTarget)));
DelayCommand(1.1, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD), oPC));
*/
// Check if item target is valid.
if (GetIsObjectValid(GetItemActivatedTarget())) return;
location lTarget = GetItemActivatedTargetLocation();
effect eFly = EffectDisappearAppear(lTarget);
DelayCommand(2.5, FadeToBlack(oPC, FADE_SPEED_FASTEST));
DelayCommand(4.2, FadeFromBlack(oPC, FADE_SPEED_FASTEST));
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eFly, oPC, 4.0);
}
else if(sTag == "faerie_fire_blue")
{
float FFDuration = IntToFloat(GetHitDice(oPC)*60);
effect FaerieAura = MagicalEffect(EffectVisualEffect(VFX_DUR_AURA_BLUE));
effect FaerieGlow = MagicalEffect(EffectVisualEffect(VFX_DUR_LIGHT_BLUE_5));
ApplyEffectToObject(DURATION_TYPE_TEMPORARY,FaerieAura,oTarget,FFDuration);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY,FaerieGlow,oTarget,FFDuration);
}
else if(sTag == "faerie_fire_green")
{
float FFDuration = IntToFloat(GetHitDice(oPC)*60);
effect FaerieAura = MagicalEffect(EffectVisualEffect(VFX_DUR_AURA_GREEN));
effect FaerieGlow = MagicalEffect(EffectVisualEffect(VFX_DUR_LIGHT_GREY_5));
ApplyEffectToObject(DURATION_TYPE_TEMPORARY,FaerieAura,oTarget,FFDuration);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY,FaerieGlow,oTarget,FFDuration);
}
else if(sTag == "faerie_fire_violet")
{
float FFDuration = IntToFloat(GetHitDice(oPC)*60);
effect FaerieAura = MagicalEffect(EffectVisualEffect(VFX_DUR_AURA_PURPLE));
effect FaerieGlow = MagicalEffect(EffectVisualEffect(VFX_DUR_LIGHT_PURPLE_5));
ApplyEffectToObject(DURATION_TYPE_TEMPORARY,FaerieAura,oTarget,FFDuration);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY,FaerieGlow,oTarget,FFDuration);
}
else SubraceCheckItemActivated(oPC, sTag);
}
//3.0.6.5
void CheckAndApplyDefaultSubrace(object oPC)
{
switch (GetRacialType(oPC))
{
case RACIAL_TYPE_DWARF:
{
SetSubRace(oPC,SUBRACE_DWARF_DEFAULT);
}
break;
case RACIAL_TYPE_ELF:
{
SetSubRace(oPC,SUBRACE_ELF_DEFAULT);
}
break;
case RACIAL_TYPE_GNOME:
{
SetSubRace(oPC,SUBRACE_GNOME_DEFAULT);
}
break;
case RACIAL_TYPE_HALFELF:
{
SetSubRace(oPC,SUBRACE_HALFELF_DEFAULT);
}
break;
case RACIAL_TYPE_HALFLING:
{
SetSubRace(oPC,SUBRACE_HALFLING_DEFAULT);
}
break;
case RACIAL_TYPE_HALFORC:
{
SetSubRace(oPC,SUBRACE_HALFORC_DEFAULT);
}
break;
case RACIAL_TYPE_HUMAN:
{
SetSubRace(oPC,SUBRACE_HUMAN_DEFAULT);
}
break;
}
}
void SubraceOnClientEnter(object oPC = OBJECT_INVALID)
{
if(!GetIsObjectValid(oPC))
{
oPC = GetEnteringObject();
}
if(!GetIsPC(oPC))
{ return; }
string subrace = GetSubRace(oPC);
//3.0.6.5
if(subrace == "")
{
if (USE_SSE_DEFAULT_RACES)
{
CheckAndApplyDefaultSubrace(oPC);
subrace = GetSubRace(oPC);
}
else
{
return;
}
}
object oArea = GetArea(oPC);
if(!GetIsObjectValid(oArea))
{
//wait for the PC to enter properly...
DelayCommand(2.0, SubraceOnClientEnter(oPC));
return;
}
if(!GetSSEInt( SUBRACE_INFO_LOADED_ON_MODULE))
{
SSE_MessageHandler(oPC, MESSAGE_MODLOAD_NOT_COMPLETE);
DelayCommand(2.0, SubraceOnClientEnter(oPC));
return;
}
DeleteLocalInt(oPC, "SUBRACE_NEEDS_TO_RELOG");
int infoLoaded = GetLocalInt(oPC, SUBRACE_INFO_LOADED_ON_PC);
if(ENABLE_LETO && !infoLoaded)
{
ExportSingleCharacter(oPC);
SetLocalString(oPC, "SUBR_PlayerName", GetPCPlayerName(oPC));
DelayCommand(5.0, SetLocalString(oPC, "SUBR_FileName", GetBicFileName(oPC)));
}
if(GetIsSSEDisabled())
{
SSE_MessageHandler(oPC, MESSAGE_SUBRACE_SSE_IS_SHUTDOWN);
return;
}
if(GetIsSSEDisabledInArea(oArea))
{
SSE_MessageHandler(oPC, MESSAGE_SUBRACE_SSE_IS_SHUTDOWN_IN_AREA);
SetLocalInt(oPC, "LOAD_SUBRACE", TRUE);
return;
}
if(!infoLoaded)
{
DelayCommand(1.0, InitiateSubraceChecking(oPC));
}
else if(infoLoaded && RELOAD_SUBRACE_INFORMATION_UPON_RELOGIN)
{
DeleteLocalInt(oPC, SUBRACE_INFO_LOADED_ON_PC);
DelayCommand(1.0, LoadSubraceInfoOnPC(oPC, subrace));
}
else
{
DelayCommand(1.0, ReapplySubraceAbilities(oPC));
}
}
void SHA_SendSubraceMessageToPC(object oPC, string message, int Important = TRUE)
{
if(MINIMALISE_SUBRACE_MESSAGES_TO_PC)
{
if(Important)
{
SendMessageToPC(oPC, SUBRACE_ENGINE + message);
}
}
else
{
SendMessageToPC(oPC, SUBRACE_ENGINE + message);
}
}
void SSE_Message_RemoveDisplayType(int MessageType)
{
int Display = SSE_Message_GetDisplayType();
Display &= (~MessageType);
SSE_Message_SetDisplayType(Display);
}
void SSE_Message_SetDisplayType(int MessageType)
{
SetSSEInt(MESSAGE_DISPLAY_CONTROL, MessageType);
}
void SSE_Message_AddDisplayType(int MessageType)
{
int Display = SSE_Message_GetDisplayType(TRUE);
Display |= (~MessageType);
SSE_Message_SetDisplayType(Display);
}
int SSE_Message_GetDisplayType(int DoNotReturnServerDefault=FALSE)
{
int Types = GetSSEInt(MESSAGE_DISPLAY_CONTROL);
if(Types)
return Types;
return DoNotReturnServerDefault?FALSE:MESSAGE_TYPE_SERVER_DEFAULT;
}
void SSE_MessageHandler(object Receiver, int MessageReference, string VariableText="", string VariableText2="", int MessageType = MESSAGE_TYPE_DEFAULT)
{
//Use MessageType's Type instead of MessageReference, if MessageType is not "default"
int Type = ( MessageType == MESSAGE_TYPE_DEFAULT ?
MessageReference & MESSAGE_HANDLER_GET_MESSAGE_TYPE
:
MessageType & MESSAGE_HANDLER_GET_MESSAGE_TYPE
);
int Message = MessageReference & MESSAGE_HANDLER_GET_MESSAGE;
//No type or no message -> nothing to do.
if(!Type || !Message) return;
int DisplayTypes = SSE_Message_GetDisplayType();
string Text = SSE_GetStandardMessage(MessageReference, VariableText, VariableText2);
//Log?
if(MESSAGE_TYPE_LOG & Type)
{
//Log is not enough to get it sent to the player as well.
Type&= (~MESSAGE_TYPE_LOG);
WriteTimestampedLogEntry(Text);
}
//Send only if we should
if( (DisplayTypes & Type) || (Type & MESSAGE_TYPE_VITAL) )
{
SendMessageToPC(Receiver, SUBRACE_ENGINE + Text);
}
}
string SSE_GetStandardMessage(int Ref, string VariableText="", string VariableText2="")
{
string Message;
switch(Ref)
{
case MESSAGE_SUBRACE_APPEARANCE_CHANGED:
Message="Your appearance has been changed to better suit your "+ SUBRACE_WHEN_ADJECTIVE +" features.";
break;
case MESSAGE_SUBRACE_APPEARANCE_REVERTED:
Message="Your appearance has been reverted back to your typical " + SUBRACE_WHEN_ADJECTIVE +" appearance.";
break;
case MESSAGE_SUBRACE_CRITERIA_FAILED:
Message="Character has failed to meet the following criteria(s) required to be part of the " + SUBRACE_WHEN_NOUN+":";
break;
case MESSAGE_CANNOT_BE_PART_OF_PRESTIGIOUS_SUBRACE:
Message="The sub-race you had chosen was a prestigious "+SUBRACE_WHEN_NOUN+". You cannot become part of this " + SUBRACE_WHEN_NOUN +" directly (Contact a DM for more info)!";
break;
case MESSAGE_FAILED_TO_MEET_PRESTIGIOUS_CLASS_RESTRICTION:
Message="You have failed to meet the prestigious class restrictions!";
break;
case MESSAGE_SUBRACE_CRITERIA_MET:
Message="You have met all the requirements for your chosen "+SUBRACE_WHEN_NOUN+"!";
break;
case MESSAGE_SUBRACE_CRITERIA_CLASS_FAILED:
Message="You have not met the class requirements for your chosen "+SUBRACE_WHEN_NOUN+".";
break;
case MESSAGE_SUBRACE_CRITERIA_SPECIAL_RESTRICTION_FAILED:
Message="You have not met the 'special' requirements for your chosen "+SUBRACE_WHEN_NOUN+". Further details on this restriction may be available from SChooser/SWand or the DMs";
break;
case MESSAGE_SUBRACE_CRITERIA_ALIGNMENT_FAILED:
Message="You have not met the alignment requirements for your chosen "+SUBRACE_WHEN_NOUN+".";
break;
case MESSAGE_SUBRACE_CRITERIA_BASE_RACE_FAILED:
Message="You are not part of the base race required in order to be part of your chosen "+SUBRACE_WHEN_NOUN+".";
break;
case MESSAGE_SUBRACE_UNRECOGNISED:
Message="You have chosen an unrecognised " + SUBRACE_WHEN_NOUN+": " + VariableText;
break;
case MESSAGE_SUBRACE_CLAWS_WAIT_FOR_CLAWS_EQUIPPING:
Message="Please wait... while your "+ SUBRACE_WHEN_ADJECTIVE +" claws are checked and " +VariableText+".";
break;
case MESSAGE_SUBRACE_CLAWS_MISSING_CREATURE_WEAPON_PROFICIENCY:
Message="You do not have creature weapon proficiency... yet your "+SUBRACE_WHEN_NOUN+" wants to equip a creature claw. Inform a DM!";
break;
case MESSAGE_SUBRACE_CLAWS_SUCCESSFULLY_EQUIPPED:
Message="Your new "+SUBRACE_WHEN_ADJECTIVE+" claws should have now been properly " + VariableText +".";
break;
case MESSAGE_SUBRACE_ACQUIRED_UNIQUE_ITEM:
Message="You have acquired "+ ColourString(VariableText,"c<>") + "; a "+SUBRACE_WHEN_ADJECTIVE +" item.";
break;
case MESSAGE_SUBRACE_EFFECTS_APPLIED:
Message=SUBRACE_WHEN_ADJECTIVE +" effects have been appiled";
break;
case MESSAGE_SUBRACE_IS_MISSING_FROM_SERVER:
Message="Data for your "+SUBRACE_WHEN_NOUN+" is missing or support for your "+ SUBRACE_WHEN_NOUN +" has been removed from the server! Contact a DM";
break;
case MESSAGE_SUBRACE_LOADING_DATA:
Message="Loading your " + SUBRACE_WHEN_NOUN+ "; " + VariableText + "'s data...";
break;
case MESSAGE_SUBRACE_DATA_LOADED:
Message="Your "+ SUBRACE_WHEN_ADJECTIVE +" data has been loaded on your character.";
break;
case MESSAGE_LETO_AUTOPORTAL:
Message=ColourString("Changes need to be made to your character; you are about to be teleported in: "+VariableText + " seconds." +"c<>");
break;
case MESSAGE_LETO_AUTOBOOT:
Message=ColourString("You will be automatically booted in: " + VariableText + " seconds.", "c<>");
break;
case MESSAGE_LETO_DONT_PANIC_JUSTPORTING:
Message=ColourString("Changes need to be made to your character; You are about to undergo an area transition... don't worry you should end up right where you are.","c<>");
break;
case MESSAGE_LETO_PLEASE_RELOG:
Message="Changes need to be made to your character; Please re-log into the server.";
break;
case MESSAGE_SUBRACE_PURGING:
Message="Purging sub-race...";
break;
case MESSAGE_SUBRACE_PURGED:
Message="Purging sub-race...DONE.";
break;
case MESSAGE_SUBRACE_SPELL_RESISTANCE_APPLIED:
Message="Your spell resistance has been modified to fit your "+ SUBRACE_WHEN_ADJECTIVE +" features.";
break;
case MESSAGE_ABILITY_SCORES_REVERTED:
Message="Your day/night ability scores have been reverted.";
break;
case MESSAGE_ABILITY_SCORES_CHANGED:
Message="Your day/night ability scores have changed...";
break;
case MESSAGE_ABILITY_SCORES_APPEARANCE_TRIGGERED_REVERTED:
Message="Your special appearance ability scores have been reverted.";
break;
case MESSAGE_ABILITY_SCORES_APPEARANCE_TRIGGERED_CHANGED:
Message="Your special appearance scores have changed...";
break;
case MESSAGE_SUBRACE_CANNOT_EQUIP_ITEM:
Message="You cannot equip this " +VariableText +" because of your "+SUBRACE_WHEN_NOUN+"'s limitations.";
break;
case MESSAGE_SUBRACE_SWITCH_CHECKING_REQUIREMENTS:
Message="Checking whether your character meets the requirements for the '" + VariableText + "' "+SUBRACE_WHEN_NOUN+"...";
break;
case MESSAGE_SUBRACE_FAILED_REQUIREMENTS_ALIGNMENT_FOR_SWITCH:
Message="Your character has failed to meet criteria for the '" + VariableText + "' " + SUBRACE_WHEN_NOUN;
break;
case MESSAGE_SUBRACE_SWITCHING:
Message="Switching sub-races to: " + VariableText;
break;
case MESSAGE_SUBRACE_SWITCHED:
Message="Sub-race was switched!";
break;
case MESSAGE_SUBRACE_FACTION_ADJUSTED:
Message="Your faction has been adjusted to fit your "+SUBRACE_WHEN_NOUN+".";
break;
case MESSAGE_SUBRACE_MOVE_TO_START_LOCATION:
Message="Welcome to " + VariableText + " " +SUBRACE_WHEN_NOUN +"'s start location.";
break;
case MESSAGE_SUBRACE_NEW_WINGS_GAINED:
Message="You have gained new wings.";
break;
case MESSAGE_SUBRACE_NEW_TAIL_GAINED:
Message="You have gained a new tail";
break;
case MESSAGE_SUBRACE_NEW_PORTRAIT_GAINED:
Message="Your character portrait has changed";
break;
case MESSAGE_SUBRACE_SSE_IS_SHUTDOWN:
Message="Subrace Engine has been switched off by a DM. Your " + SUBRACE_WHEN_NOUN + " will not function.";
break;
case MESSAGE_SUBRACE_SSE_IS_SHUTDOWN_IN_AREA:
Message="Subrace Engine is switched off in this area.";
break;
case MESSAGE_SUBRACE_APPEARANCE_DATA_ERROR:
Message="Appearance data error! Re-login to fix this problem.";
break;
case MESSAGE_SUBRACE_GENDER_FAILED:
Message="You have not met the gender requirements for the chosen " + SUBRACE_WHEN_NOUN + ".";
break;
case MESSAGE_SUBRACE_FAILED_CRITERIA_SO_REMOVED:
Message="Your " + SUBRACE_WHEN_NOUN + " has been removed because you did not meet the criteria(s).";
break;
case MESSAGE_SUBRACE_ALIAS_UNIFORMIZING:
Message=VariableText + " is an alias for " + VariableText2 + ". Uniformizing.";
break;
case MESSAGE_SUBRACE_ALIAS_DIVERSITY:
Message="Alias detected, using: " + VariableText + "'s properties.";
break;
case MESSAGE_MODLOAD_NOT_COMPLETE:
Message="Waiting for Module to load subraces...";
break;
case MESSAGE_USER_MADE:
Message=VariableText + VariableText2;
break;
}
return Message;
}
int GetPlayerSubraceID(object Player)
{
return GetSubraceID(GetSubRace(Player));
}
//Subrace Default Heartbeat. (For use in default.nss)
//
//Version 2.7 Alpha: Much improved version of the heartbeat.
// Some of the weights of the checks and things are taken off
// the script by an external timer object that triggers during
// day night transition.
//
// Added: SubraceStorage + "_" + SUBRACE_HAS_DAY_NIGHT_EFFECTS -- an int
// that stores TRUE if the subrace has temporary stats or
// has light sensitivity, damaged by light etc (IE: Like Drow or Vampire)
//
//--- These should reduce the weight on the CPU significantly.
void SubraceHeartbeat(object oPC = OBJECT_SELF)
{
if(GetLocalInt(oPC, "LOAD_SUBRACE"))
{
if(!GetSSEStatus(GetArea(oPC)) )
{
DelayCommand(1.0, InitiateSubraceChecking(oPC));
DeleteLocalInt(oPC, "LOAD_SUBRACE");
}
return;
}
int ID = GetPlayerSubraceID(oPC);
if(!ID || !GetLocalInt(oPC, SUBRACE_INFO_LOADED_ON_PC))
{ return; }
object oArea = GetArea(oPC);
if(GetSSEStatus(oArea))
{
return;
}
string SubraceStorage = GetSubraceStorageLocationByID(ID);
if(GetSSEInt( SubraceStorage + "_" + SUBRACE_HAS_DAY_NIGHT_EFFECTS))
{
int iTime = SHA_GetCurrentTime();
int AreaLocation = GetIsAreaAboveGround(oArea);
int Interior = GetIsAreaInterior(oArea);
int Natural = GetIsAreaNatural(oArea);
int HasDiffStats = GetSSEInt( SubraceStorage + "_" + SUBRACE_STAT_MODIFIERS);
if(HasDiffStats > 0)
{
ApplyTemporarySubraceStats(oPC, SubraceStorage, iTime, AreaLocation, Interior, Natural);
}
if(iTime == TIME_DAY)
{
if(AreaLocation == AREA_ABOVEGROUND && !Interior)
{
int IsLightSens = GetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_LIGHT_SENSITIVE, SUBRACE_BASE_INFORMATION_FLAGS);
int DmgTakenL = GetSSEInt( SubraceStorage + "_" + DAMAGE_AMOUNT_IN_LIGHT);
if(IsLightSens)
{
ApplyLightSensitivity(oPC);
}
if(DmgTakenL)
{
ApplyDamageWhileInLight(oPC, DmgTakenL);
}
}
else if(AreaLocation == AREA_UNDERGROUND)
{
int IsUndergSens = GetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_UNDERGROUND_SENSITIVE, SUBRACE_BASE_INFORMATION_FLAGS);
int DmgTakenU = GetSSEInt( SubraceStorage + "_" + DAMAGE_AMOUNT_IN_UNDERGROUND);
if(IsUndergSens)
{
ApplyUndergroundSensitivity(oPC);
}
if(DmgTakenU)
{
ApplyDamageWhileInDark(oPC, DmgTakenU);
}
}
}
else if(iTime == TIME_NIGHT)
{
if(AreaLocation == AREA_UNDERGROUND)
{
int IsUndergSens = GetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_UNDERGROUND_SENSITIVE, SUBRACE_BASE_INFORMATION_FLAGS);
int DmgTakenU = GetSSEInt( SubraceStorage + "_" + DAMAGE_AMOUNT_IN_UNDERGROUND);
if(IsUndergSens)
{
ApplyUndergroundSensitivity(oPC);
}
if(DmgTakenU)
{
ApplyDamageWhileInDark(oPC, DmgTakenU);
}
}
}
}
}