//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: //:::::::::::::::::::::::: 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_ 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_ 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(). // // :: 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_ 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 /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("You are unable to fly in this location!!", 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); } } } } }