· 9 years ago · Jan 06, 2017, 05:12 PM
1//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
2//:::::::::::::::::::::::: Shayan's Subrace Engine :::::::::::::::::::::::::::::
3//::::::::::::::::::::::: File Name: sha_subr_methds :::::::::::::::::::::::::::
4//:::::::::::::::::::::::::: Include script ::::::::::::::::::::::::::::::::::::
5//:: Written by: Shayan
6//:: Contributed to by: Moon, Parsec, TwentyOneScore :://
7//:: Contact: mail_shayan@yhaoo.com :://
8//:: Forums: http://p2.forumforfree.com/shayan.html
9//
10// ::Description: Holds all the methods used in the Subrace System. DO NOT CHANGE
11// :: ANYTHING UNLESS YOU ARE CERTAIN.
12// :: This is the 'core engine script'. In updates, more than likely
13// :: this script is changed... so unless you do not plan to update to
14// :: possible future releases of this engine, it will be in your best
15// :: interest NOT to make any changes to this script. Because then you
16// :: will have to redo them again.
17// :: Should you disregard this warning and proceed to editing...
18// :: Remember that:
19// :: * If you have made a change you must recompile all scripts for
20// :: changes to take place.
21//
22// ::Please refer to the script file 'sha_subr_consts' to change any values of the
23// ::constants or default values.
24
25// ::Version 3.0.5: Spring cleaned by Moon.
26
27// ::Version 1.4: Reduced the numbers of local variables, by "encoding a single integer
28// :: variable to hold several 'bits' of information". - Using Axe Murderer's Flag-sets.
29
30// ::Version 1.2: Support for NWNX added.
31
32//#include "sha_subr_consts - Gained through sha_misc_funcs AND sha_leto_inc
33
34//NWNX Database script.
35#include "aps_include"
36
37//NWN standard switch library.
38#include "x2_inc_switches"
39
40#include "sha_misc_funcs"
41
42// :: Version 2.5: LETO Include functions.
43#include "sha_leto_inc"
44
45// :: Version 3.0.5b3: Made Spellhooks loading a part of the OnModLoad event
46// :: Thus x2_inc_switches was required
47// :: 3.0.6 removed cuz its up there a few lines ago :p
48//#include "x2_inc_switches"
49
50//::****************************************************************
51// 1.69 -- Support for horses
52#include "x3_inc_skin"
53//::****************************************************************
54
55//:: - ALL SUBRACE RELATED METHODS MUST BE CALLED AFTER THIS METHOD! -
56//:: -- The Main function. Call this OnModuleLoad.
57//
58// ::Race: This is the base race that you want to create your subrace from
59// :: Use ONLY: RACIAL_TYPE_ALL, or RACIAL_TYPE_DWARF, RACIAL_TYPE_ELF,
60// :: RACIAL_TYPE_GNOME, RACIAL_TYPE_HALFELF, RACIAL_TYPE_HALFLING,
61// :: RACIAL_TYPE_HALFORC, or RACIAL_TYPE_HUMAN.
62// :: If you want to add additional races that can become part of this subrace call
63// :: AddAdditionalBaseRaceToSubrace() AFTER this method.
64//
65// ::subrace: The subrace's name. This is what the PC will have to type in his/her
66// :: Subrace field. DO NOT HAVE SPACES IN NAMES.
67// :: IE: Use "Dark-elf" NOT "Dark elf".
68// :: (Not case sensitive.)
69//
70// ::HideResRef: This is the resref of the Creature Hide/Skin you want to equip on the PC.
71// :: This will have all the subrace traits like ability modifiers and base feats etc.
72//
73// :: If you do not want a skin, write either "none" or leave it as blank.
74//
75// ::UniqueItemResref: This is the resref of the item that you want given to the player. For example this item
76// :: could hold can spells on it, or just description of the subrace. Ideally this item will not be droppable,
77// :: 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.
78// :: (If they lose it or drop it they will again get it back on the next time they enter).
79//
80// :: If you do not want to give the PC a unique item then, write either "none" or leave it as blank.
81//
82// ::IsLightSensitive: Set to TRUE if the subrace is light senstive. IE: Blinded when in Sunlight and/or gets saves and AB decreases.
83// :: If the PC does not pass the fort saving throw, then it is blinded for that round.
84// :: The DC for the saving throw can be changed by changing the value of
85// :: LIGHT_SENSITIVE_SAVING_THROW_DC in the file sha_subr_consts. Also you can change the interval (rounds) between each time the PC
86// :: is 'struk' by light by changing the value of LIGHT_BLINDNESS_STRIKES_EVERY_ROUND. And also you can change the number of rounds
87// :: the PC stays blinded for if it fails the saving throw by changing tha value of LIGHT_STRUCK_BLIND_FOR_ROUNDS.
88//
89// :: If APPLY_AB_AND_SAVING_THROW_DECREASES_IN_LIGHT is set to TRUE, then the PC also suffers
90// :: an attack bonus decrease of LIGHT_AB_DECREASE and saving throw decrease of LIGHT_SAVE_DECREASE for a number of rounds
91// :: determined by: LIGHT_CAUSES_AB_AND_SAVES_DECREASE_FOR_ROUNDS.
92//
93// :: Rememeber: IF YOU CHANGE ANYTHING IN THE CONSTANTS FILE, IT WILL APPLY TO ALL SUBRACES.
94// :: (IE: If you change the DC for the saving throw then all subraces that have light sensitivity will have to make that saving throw).
95//
96// ::DamageTakenWhileInLight: The amount of divine Damage the PC suffers ever round while
97// :: it is in sunlight. Note: PC does not necessarily have to be Light Sensitive
98// :: for this to work.
99// :: If this value is negative then the PC will regenerate that amount.
100//
101// ::IsUndergroundSensitive: Same as IsLightSenstive but this applies when the PC is in
102// :: Underground type of areas. This does not mean the PC is affected by Night time.
103//
104// ::DamageTakenWhileInUnderground: The amount of Negative Damage taken per round while in the Underground.
105// :: Note: This too doesn't need the PC to be Under ground sensitive to apply.
106// :: If this value is negative then the PC will regenerate that amount.
107//
108// :: ECL: Effective Character Level: Use any integer value.
109// :: (For those that do not know what this is...
110// :: Effective Character Level is a way of lessening your subrace's bonus abilities
111// :: by reducing the amount of experience points gained per kill.)
112// :: IE: If you have a Subrace with ECL of 3, then a PC (Player character) of level 10 belonging to
113// :: that subrace is regarded being level 13 when gaining XP points per kill.
114// :: Thus will get less experience points.
115// :: NOTE: This can work for negative values as well.
116//
117// :: IsUndead: Mark the PC belonging to this sub-race as being Undead. It will mean that Healing spells will hurt the PC.
118// :: And harming spells will heal the PC.
119//
120// :: 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.
121// :: (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)
122// :: -Refer to SetupSubraceSwitch() for more information -
123//
124// :: Example: You wish to create a subrace called Drow, and you have created a Creature Skin/Hide in the toolset with
125// :: resref "sha_pc_drow". The Unique item (which contains spell like abilities and information about the Drow subrace)
126// :: has the resref "sha_subrace_drow". And you want to make the Drow light sensitive and take 2 divine damage while in light areas.
127// :: Also you would like to mark the Drow as having an Effective Character level of +1.
128// :: Simply call this OnModuleLoad. (Remember to #include "sha_subr_methds", in the script)
129//
130// :: CreateSubrace(RACIAL_TYPE_ELF, "drow", "sha_pc_drow", "sha_subrace_drow", TRUE, 2, FALSE, 0, 1);
131void 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);
132
133
134//- Add another Race that can be part of the subrace.
135// :: subrace should be the same as the Subrace's name used in CreateSubrace()
136// :: AdditionalBaseRace can only be RACIAL_TYPE_ALL, RACIAL_TYPE_DWARF, RACIAL_TYPE_ELF, RACIAL_TYPE_GNOME,
137// :: RACIAL_TYPE_HALFELF, RACIAL_TYPE_HALFLING, RACIAL_TYPE_HALFORC, or RACIAL_TYPE_HUMAN.
138void AddAdditionalBaseRaceToSubrace(string subrace, int AdditionalBaseRace);
139
140
141// ::Limit the classes the PC can be, when trying to be part of this subrace.
142// :: subrace should be the same as the Subrace's name used in CreateSubrace()
143// :: Set the CanBe_<Class> values as desired.
144//
145// ::Note: This will only check PC's first class. IE: You limit your subrace's classes to only Fighter and Rogue
146// :: A player with classes Wizard/Fighter/Cleric will not meet the criteria, nor will a Monk/Cleric/Rogue.
147// :: Only a PC with either Rogue or Fighter as their first class will meet the requirement.
148// :: IE: Rogue/WeaponMaster or Fighter/Wizard/Cleric.
149void 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);
150
151
152//Limit the Alignment the PC can be, when trying to be part of this subrace.
153//Note this alignment restriction only applies when the PC enters the module for the first time. (A database entry is made).
154// :: IE: It will not stop the PC from being part of the subrace after the PC adventures and changes in alignment.
155//
156// :: subrace should be the same as the Subrace's name used in CreateSubrace()
157// :: Set the CanBe_<Alignment> to as desired.
158void 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);
159
160
161//Use this method of Spell resistance if you want the Spell resistance to increase (or decrease) with the PC's level.
162// :: subrace should be the same as the Subrace's name used in CreateSubrace()
163//
164// :: SpellResistanceBase: Is the vaule of SR the PC gains at level 1
165// :: 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")
166void CreateSubraceSpellResistance(string subrace, int SpellResistanceBase, int SpellResistanceMax);
167
168
169//Use this method if you want the PC's Appearance to change for the subrace.
170//
171// :: subrace should be the same as the Subrace's name used in CreateSubrace()
172// :: AppearanceChangeTime: Time of day you want the Appearance to change.
173// :: if you want to have a permanent appearance change then use: TIME_BOTH.
174// :: 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.
175// :: 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.
176// :: if you plan on making a controlable appearance, then set to TIME_NONE. (Refer to manual for more information)
177//
178// ::MaleAppearance: This is the appearance of a Male PC. Use any of the APPEARANCE_TYPE_* values.
179// ::FemaleAppearance: This is the appearance of a Female PC. Use any of the APPEARANCE_TYPE_* values.
180// ::Level: From which level to apply this appearance change from...
181//
182// ::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),
183// :: Then your appearance will be different... (in the case of wyrmiling, you will look like a mephit) - You have been warned.
184void CreateSubraceAppearance(string subrace, int AppearanceChangeTime, int MaleAppearance, int FemaleAppearance, int Level = 1);
185
186// - (You may use this twice per subrace. Once for TIME_DAY, and once for TIME_NIGHT) -
187//
188// Use this method if you want the PC's ability scores or AC or AB to change when it is either day or night.
189// (The use of this function is slightly more complicated)
190//
191// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
192//
193// :: struct SubraceStats Stats: (Explained below)
194//
195// :: 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.
196// :: 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.
197//
198// :: InInteriorArea: Set to TRUE if you want these changes to ability scores to happen in Interior Areas.
199// :: InExteriorArea: Set to TRUE if you want these changes to ability scores to happen in Exterior Areas.
200// :: InNaturalArea: Set to TRUE if you want these changes to ability scores to happen in Natural Areas.
201// :: InArtifacialArea: Set to TRUE if you want these changes to ability scores to happen in Artifical Areas.
202// :: InUndergroundArea: Set to TRUE if you want these changes to ability scores to happen in Underground Areas.
203// :: InAbovegroundArea: Set to TRUE if you want these changes to ability scores to happen in Above Ground Areas.
204//
205// :: How to use this function.
206//
207// :: First create a structure of SubraceStats. It can be done by:
208//
209// :: struct SubraceStats mystats = CreateCustomeStats(<fill in appropriate values. Look at CreateCustomeStats method for more details>).
210//
211// :: then you want to add this to your subrace. So call
212//
213// :: CreateTemporaryStatModifier("mysubrace", mystats, TIME_DAY, TRUE, FALSE);
214//
215// ::Hence the PC belonging to "mysubrace" will have it's ability scores changed during day time, when they are in Exterior (IE: outdoors) areas.
216void 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);
217
218
219//This is the first half of CreateTemporaryStatModifier function.
220//
221//(The use of this function is slightly more complicated)
222//
223// :: 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)
224// :: or SUBRACE_STAT_MODIFIER_TYPE_POINTS (if you wish to increase or decrease a PC's ability scores/AC/AB by constant number.
225// :: Fill in the values of the floats appropriately.
226//
227// ::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%.
228//
229// ::so you create your stats:
230//
231// ::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);
232//
233// ::You then use this in CreateTemporaryStatModifier().
234struct SubraceStats CreateCustomStats(int StatModifierType, float StrengthModifier, float DexterityModifier, float ConstitutionModifier, float IntelligenceModifier, float WisdomModifier, float CharismaModifier, float ACModifier, float ABModifier);
235
236
237// Restricing the use of Items (both weapons and armour) for a given subrace.
238// Use this for each of the four TimeOfDay you want. (TIME_DAY, TIME_NIGHT, TIME_SPECIAL_APPEARANCE_NORMAL and TIME_SPECIAL_APPEARANCE_SUBRACE)
239// ItemType should be a mix of the following (mix them by using | ):
240//
241// --------- Weapon Restrictions ---------
242//
243//
244// - ITEM_TYPE_WEAPON_MELEE - Melee Weapons (incl. Monk Gloves) Does NOT include Bracers.
245// - ITEM_TYPE_WEAPON_RANGED_THROW - Ranged Weapons (Throwing Weapons)
246// - ITEM_TYPE_WEAPON_RANGED_LAUNCHER - Ranged Weapons (Launchers) Does "incl." Ammonition (Ammo can still be equipped but is not usable)
247// - ITEM_TYPE_WEAPON_RANGED - Ranged Weapons (Both Launchers and Throwing)
248// - ITEM_TYPE_WEAPON - All Weapons (Both Ranged and Melee)
249//
250// - ITEM_TYPE_WEAPON_PROF_SIMPLE - Simple Weapons
251// - ITEM_TYPE_WEAPON_PROF_MARTIAL - Martial Weapons
252// - ITEM_TYPE_WEAPON_PROF_EXOTIC - Exotic Weapons
253// - ITEM_TYPE_WEAPON_PROF_ANY - All Weapon Prof.
254//
255// - ITEM_TYPE_WEAPON_SIZE_TINY - Tiny Weapons
256// - ITEM_TYPE_WEAPON_SIZE_SMALL - Small Weapons
257// - ITEM_TYPE_WEAPON_SIZE_MEDIUM - Medium Weapons
258// - ITEM_TYPE_WEAPON_SIZE_LARGE - Large Weapons
259//
260// - ITEM_TYPE_WEAPON_SIZE_SMALL_DOWN - All Small or smaller Weapons (Small, Tiny)
261// - ITEM_TYPE_WEAPON_SIZE_MEDIUM_UP - All Medium or Larger Weapons (Medium, Large)
262// - ITEM_TYPE_WEAPON_SIZE_ANY - All Weapon Sizes.
263//
264//
265//
266// --------- Armour, Helm and Shield Restrictions ---------
267//
268// - ITEM_TYPE_SHIELD_SMALL - Small Shields
269// - ITEM_TYPE_SHIELD_LARGE - Large Shields
270// - ITEM_TYPE_SHIELD_TOWER - Tower Shields
271// - ITEM_TYPE_SHIELD_ANY - All Shields.
272//
273// - ITEM_TYPE_ARMOR - Torso Armour Only (AC 0-8)
274// - ITEM_TYPE_ARMOR_TYPE_CLOTH - Cloth Torso Armour only (AC 0)
275// - ITEM_TYPE_ARMOR_TYPE_LIGHT - Light Torso Armour only (AC 1-3)
276// - ITEM_TYPE_ARMOR_TYPE_MEDIUM - Medium Torso Armour only (AC 4-6)
277// - ITEM_TYPE_ARMOR_TYPE_HEAVY - Heavy Torso Armour only (AC 7-8)
278//
279// - ITEM_TYPE_ARMOR_AC_0 - Torso Armour with 0 AC
280// - ITEM_TYPE_ARMOR_AC_1 - Torso Armour with 1 AC
281// - ITEM_TYPE_ARMOR_AC_2 - Torso Armour with 2 AC
282// - ITEM_TYPE_ARMOR_AC_3 - Torso Armour with 3 AC
283// - ITEM_TYPE_ARMOR_AC_4 - Torso Armour with 4 AC
284// - ITEM_TYPE_ARMOR_AC_5 - Torso Armour with 5 AC
285// - ITEM_TYPE_ARMOR_AC_6 - Torso Armour with 6 AC
286// - ITEM_TYPE_ARMOR_AC_7 - Torso Armour with 7 AC
287// - ITEM_TYPE_ARMOR_AC_8 - Torso Armour with 8 AC
288//
289// - ITEM_TYPE_HELM - Helms
290//
291// - ITEM_TYPE_FULL_ARMOR_SET - All Armours, Shields and Helms.
292//
293// --------- Misc. Restrictions ---------
294//
295// - ITEM_TYPE_JEWLERY - Rings and Amulets
296// - ITEM_TYPE_MISC_CLOTHING - None-Torso clothing (Cloak, Braces, Boots) Does NOT include Jewlery
297// - ITEM_TYPE_NONE_BIOWARE_ITEM - ALL None Standard Bioware Items (e.g. CEP Items)
298//
299//
300//
301// TimeOfDay should either be any mix of TIME_DAY,TIME_NIGHT, TIME_BOTH for time-based restrictions OR
302// a mix of TIME_SPECIAL_APPEARANCE_SUBRACE, TIME_SPECIAL_APPEARANCE_SUBRACE for appearance-based restrictions.
303// Appearance-based will override Time-based in case of conflict!
304//
305// Allow should be a mix of the follow constants:
306// - 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
307// - ITEM_TYPE_REQ_ANY - Must just meet one of the requirements e.g. Large Weapons or simple weapons can be used.
308// - ITEM_TYPE_REQ_DO_NOT_ALLOW - Subrace CANNOT use ItemType during TimeOfDay (input is reversed)
309void SubraceRestrictUseOfItems(string subrace, int ItemType, int TimeOfDay = TIME_BOTH, int Allow = ITEM_TYPE_REQ_DO_NOT_ALLOW);
310
311
312//:: Add a favored class to the subrace.
313//
314// (Use this only ONCE per subrace. It will not work correctly if used more than once per subrace)
315// This would mean that when determining XP penalty for multiclassing, the favored
316// classes do not apply when determining it (Works the same way as default NWN favored classes)
317// ::(This will work ONLY if you are using the attached Shayan's XP System script).
318//
319//NOTE: You can use any playable base CLASS_TYPE_* constant. Do NOT USE Prestige classes,
320// :: as they are not taken into consideration when determining multiclassing penalty by NWN.
321// :: Also if you do specify a prestige class it will end up giving players a 20% boost to the XP gained.
322// :: (Thanks to Masterlexx for spotting this bug)
323void AddSubraceFavoredClass(string subrace, int MaleFavoredClass, int FamaleFavoredClass);
324
325//Add a permanent or a temporary subrace effect on the PC, during day or night or permanently.
326//
327//:: subrace: Should be the same as the Subrace's name used in CreateSubrace()
328//:: EffectID: There are a limited number of effects you can use here...
329//:: EFFECT_TYPE_ARCANE_SPELL_FAILURE
330//:: EFFECT_TYPE_BLINDNESS
331//:: EFFECT_TYPE_CHARMED
332//:: EFFECT_TYPE_CONCEALMENT
333//:: EFFECT_TYPE_CONFUSED
334//:: EFFECT_TYPE_CUTSCENEGHOST
335//:: EFFECT_TYPE_HASTE
336//:: EFFECT_TYPE_IMMUNITY
337//:: EFFECT_TYPE_IMPROVEDINVISIBILITY
338//:: EFFECT_TYPE_INVISIBILITY
339//:: EFFECT_TYPE_MISS_CHANCE
340//:: EFFECT_TYPE_MOVEMENT_SPEED_DECREASE
341//:: EFFECT_TYPE_MOVEMENT_SPEED_INCREASE
342//:: EFFECT_TYPE_POLYMORPH
343//:: EFFECT_TYPE_REGENERATE
344//:: EFFECT_TYPE_SANCTUARY
345//:: EFFECT_TYPE_SLOW
346//:: EFFECT_TYPE_TEMPORARY_HITPOINTS
347//:: EFFECT_TYPE_TRUESEEING
348//:: EFFECT_TYPE_ULTRAVISION
349//:: EFFECT_TYPE_VISUALEFFECT
350//
351// :: Value1: This is the value of the first parameter (from left) that you can input for the effect.
352// :: IE: If you choose EFFECT_TYPE_CONCEALMENT, which means the effect applied will be:
353// :: EffectConcealment(int nPercentage, int nMissType=MISS_CHANCE_TYPE_NORMAL)
354// :: Thus Value1 will be the value of nPercentage.
355// :: YOU MUST INPUT A VALUE! IF NOT THE SCRIPT WILL PUT IN 0!!
356//
357// :: Value2: This is the value of the second parameter you can input for the effect.
358// :: IE: (Refer to Value1's example) This will be the value of nMissType.
359// :: YOU MUST INPUT A VALUE! IF NOT THE SCRIPT WILL PUT IN 0!!
360//
361// ::nDurationType: Duration type of the effect being applied...
362// :: DURATION_TYPE_INSTANT, DURATION_TYPE_PERMANENT, or DURATION_TYPE_TEMPORARY.
363//
364// ::fDuration: The number of seconds the effect should last for...
365// :: (Put 0.0 if you are making it last "forever" -IE: Whole of day time, or night time or permanetly)
366//
367// ::TimeOfDay: The time of day you want this applied. Use TIME_BOTH if you want this permanently applied on the PC.
368//
369// Use as many times as desired.
370void AddSubraceEffect(string subrace, int EffectID, int Value1, int Value2, int nDurationType, float fDuration, int TimeOfDay);
371
372//Add a different skin to the subrace at specified level. (Use as many times as desired)
373//
374//:: subrace: Should be the same as the Subrace's name used in CreateSubrace()
375//:: SkinResRef: The Blueprint ResRef of the skin that you want the subrace to be equipped.
376//:: EquipLevel: The level at which you want the skin to be applied.
377//:: iTime: The time at which you want the skin to be equipped. (Use TIME_DAY, TIME_NIGHT, or TIME_BOTH.)
378//
379// ::Example: You want to add a skin for the subrace Illithid to use at level 15, during day time.
380//
381// ::Then call onModuleLoad script:
382// :: AddAdditionalSkinsToSubrace("Illithid", "my_illithid_skin", 15, TIME_DAY);
383//
384// ::(Where "my_illithid_skin" is the resref of the skin you want equipped.)
385//
386// ::::
387// :::: Remeber: If you say add a skin for a subrace to be equipped at level 15, then all PCs belonging to the
388// :::: subrace above level 15 will also use the same skin for that time -unless you add a different skin for those levels.)
389//
390// ::::Use as many times as desired.
391void AddAdditionalSkinsToSubrace(string subrace, string SkinResRef, int EquipLevel, int iTime = TIME_BOTH);
392
393
394//::: Add equipable creature claws to the subrace. (Use as many times as desired)
395//
396// :: This allows you to add 'Claws' to your subrace. You simply specify the Blue print resref of
397// :: the claw you want equipped on the player, and at what level.
398// :: (You can use this to equip claws/slams/gore or what ever else that maybe equipped in a PC's claw item slots
399//
400//
401//:: subrace: Should be the same as the Subrace's name used in CreateSubrace()
402//:: 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.)
403//:: 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.)
404//:: EquipLevel: The level at which these claws should be equipped.
405//
406// ::NOTE: 1. Make sure the PCs have weapon proficiency in creature weapons!!! I can't stress this enough.
407// :: (Give the feat through the subrace Skin)
408//
409// :: 2. If you are going to use one claw, make sure it is the right claw.
410//
411// :: 3. Also note that you need not change both claws at once.
412// :: (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
413// :: then you only need to specify the resref of the left claw... the PC keeps the existing right claw.)
414void AddClawsToSubrace(string subrace, string RightClawResRef, string LeftClawResRef , int EquipLevel, int iTime = TIME_BOTH);
415
416
417//::: Switch the player from one subrace to another ::::
418//
419// ::(Use only once per Level)
420//
421// :: This allows you to switch a player from one subrace to another.
422//
423//:: subrace: Should be the same as the Subrace's name used in CreateSubrace()
424//:: 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())
425//:: Level: The level at which this switch should take place.
426//:: MustMeetRequirements: Set to FALSE, if you want the switching to bypass any class/race/alignment restriction the new subrace might have.
427//
428// :: 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.
429//
430// ::IDEA: You can set the subrace you want the player to switch to as a hidden and unaccessible subrace for new characters, by setting
431// :: PrestigiousSubrace to TRUE, in CreateSubrace().
432// :: That way, players must earn their way to this new subrace (switchSubraceNames).
433//
434// ::Note: In order for this to work the subrace you wish to switch the player to does NOT have to be marked as prestigious.
435//
436// ::IE: If I had set up three subraces like:
437// :: CreateSubrace(RACIAL_TYPE_HUMAN, "illithid", "sha_pc_illithid", "sha_subrace_illi", TRUE, 0, FALSE, 0, 3);
438// :: //(Along with other setting for subrace, like class restrictions, appearance, additional skins, etc)
439//
440// :: CreateSubrace(RACIAL_TYPE_HUMAN, "vampire", "sha_pc_vamp001", "sha_subrace_vamp", TRUE, 2, FALSE, 0, 3, TRUE);
441// :: //Can only be evil.
442// :: CreateSubraceAlignmentRestriction("vampire", FALSE, FALSE, TRUE);
443// :: //(Along with other setting for subrace, like class restrictions, appearance, additional skins, etc)
444//
445// :: CreateSubrace(RACIAL_TYPE_HUMAN, "wolkier", "sha_pc_wolk", "sha_subrace_wolk", TRUE);
446// :: //Can only be Neutral;.
447// :: CreateSubraceAlignmentRestriction("wolkier", FALSE, TRUE, FALSE);
448// :: //(Along with other setting for subrace, like class restrictions, appearance, additional skins, etc)
449//
450// ::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:
451//
452// :: SetupSubraceSwitch("illithid", "vampire_wolkier", 15, TRUE);
453//
454// ::If I didn't want the alignment criteria to be check during switching then I would call:
455//
456// :: SetupSubraceSwitch("illithid", "vampire_wolkier", 15, FALSE);
457//
458// :: 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.
459//
460//
461// :: You can put in any number of subraces to switch to..
462// :: IE:
463// SetupSubraceSwitch("illithid", "vampire_wolkier_pixie_shadow", 8, TRUE);
464//
465// If a player doesn't meet the criteria for any one of the subraces, he/she wil remain part of thier usual/current subrace.
466//
467// You can use SetupSwitchSubrace() as many times as you like. EG:
468//
469// SetupSubraceSwitch("illithid", "vampire_wolkier_pixie_shadow", 12, TRUE);
470// SetupSubraceSwitch("illithid", "air-genasi_underminion", 18, TRUE);
471// SetupSubraceSwitch("illithid", "mindbreaker_telephathest_darkmoon", 32, TRUE);
472// SetupSubraceSwitch("illithid", "greatone", 40, FALSE);
473//
474// Where: vampire, wolkier, pixie, shadow, air-genasi, underminion, mindbreaker,
475// telephathest, darkmoon, and greatone are all subraces.
476void SetupSubraceSwitch(string subrace, string switchSubraceName, int Level, int MustMeetRequirements = TRUE);
477
478// :: Give the player belonging to a subrace, additional unique items ::
479// (Use as many times as desired for any levels)
480//
481// This allows you to give players belonging to a subrace additional unique items, at any level.
482//
483// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
484// :: ItemResRef: The blueprint res-ref of the item to give.
485// :: Level: The level at which to give the item.
486//
487// Example:
488//
489// Say I wanted to give my players belonging to the vampire subrace, an armour and a scythe at level 2.
490// And then an amulet at level 10.
491// The armor's resref is: "sha_vamp_arm"
492// The scythe's resref is: "sha_vamp_scythe"
493// The amulet's resref is: "sha_vamp_ammy"
494//
495// So I simply call:
496// AddSubraceItem("vampire", "sha_vamp_arm", 2);
497// AddSubraceItem("vampire", "sha_vamp_scythe", 2);
498// AddSubraceItem("vampire", "sha_vamp_ammy", 10);
499//
500//// NOTE: You can only give ONE item of each. IE: You CAN'T do this expecting to give 2 amulets:
501//
502// AddSubraceItem("vampire", "sha_vamp_ammy", 10);
503// AddSubraceItem("vampire", "sha_vamp_ammy", 10);
504void AddSubraceItem(string subrace, string ItemResRef, int Level = 1);
505
506// :: Setup an alias for your subrace.
507//
508// Allows you to use two or more "names" for the same subrace without
509// having to add it twice.
510//
511// See SSE_TREAT_ALIAS_AS_SUBRACE in sha_subr_consts for more info.
512void SetupSubraceAlias(string subrace, string Alias);
513
514
515// :: Setup a Prestige class restriction for a 'Prestige' subrace.
516//
517// NOTE: This will only be checked during a 'subrace switch' for obvious reasons. Refer to SetupSubraceSwitch(...)
518//
519// subrace = Should be the same as the Subrace's name used in CreateSubrace().
520// MinimumLevels = The minimum number of levels in a/any particular prestigious class allowed to pass the restriction.
521// Set CanBe_<Class> values as desired.
522//
523// Example:
524//
525// 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.
526// AND they must have atleast 5 levels in any of those classes.
527// So I set:
528//
529// CreateSubracePrestigiousClassRestriction("phantasm", 5, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE);
530//
531// * A player with class combination like <Any base class>/Assasin(2)/ShadowDancer(3) will meet this criteria.
532//
533// NOTE: This can be used in combination with CreateSubraceClassRestriction(...)
534//
535// 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.
536void 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);
537
538// :: Add wings or tail to the subrace ::
539//
540// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
541// :: Male_Wings: The wing to be added for a male character: Use any APPEARANCE_TYPE_ATTACHMENT_WINGS_* constant.
542// :: Female_Wings: The wing to added for a female character: Use any APPEARANCE_TYPE_ATTACHMENT_WINGS_* constant.
543// :: Male_Tail: The tail to be added for a male character: Use any APPEARANCE_TYPE_ATTACHMENT_TAIL_* constant.
544// :: Female_Tail: The tail to be added for a female character: Use any APPEARANCE_TYPE_ATTACHMENT_TAIL_* constant.
545// :: Level: The level at which to add these attachments.
546// NOTE: If you are using any of the CEP tails or wings, your server/module must have CEP.
547//
548// Example of Usage:
549//
550// Say I want to add bird like wings to the male character, and angel wings to the female character at level 21:
551// 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.
552//
553//
554// AddSubraceAppearanceAttachment("mysubrace", APPEARANCE_TYPE_ATTACHMENT_WINGS_BIRD, APPEARANCE_TYPE_ATTACHMENT_WINGS_ANGEL, 0, 0, 21);
555// 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);
556//
557//
558//:: You may use this as many times as desired.
559void ModifySubraceAppearanceAttachment(string subrace, int Male_Wings = 0, int Female_Wings = 0, int Male_Tail = 0, int Female_Tail = 0, int Level = 1);
560
561
562// :: Use to restrict subrace's gender ::
563//
564// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
565// :: CanBeMale: Set to FALSE if you do not want the subrace to be playable by Male characters
566// :: CanBeFemale: Set to FALSE if you do not want the subrace to be playable by Female characters
567//
568// :: Example of useage:
569// Say I want my subrace "Pixie" only be playable by Female characters... then I would call:
570//
571// CreateSubraceGenderRestriction("pixie", FALSE, TRUE);
572void CreateSubraceGenderRestriction(string subrace, int CanBeMale = TRUE, int CanBeFemale = TRUE);
573
574// :: Use to the portrait of a character ::
575//
576// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
577// :: MalePortrait: Set the name of the male portrait.
578// :: FemalePortrait: Set the name of the female portrait.
579// :: Level: The level at which to change the portrait.
580//
581// List of portraits' file names can be found in portraits.2da.
582//
583// NOTE: This function will correclty set the portraits. But whether or not other players or the player him/herself can see
584// it depends on whether they have portrait in their portrait folder or the expansion packs containing the portraits.
585// (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
586// portrait folder will not be able to see them. And other players without HoTU will not be able to see the player's portrait)
587//
588// NOTE 2: If you want to use any of the standard portraits (That is any from NWN) make sure you have "po_" as prefix.
589// 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_.
590// (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)
591//
592// Example of Useage:
593// 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.
594// So this means that this portrait set is refered to by: po_queenshao_
595// Likewise say I have another portrait set: my_male_port_
596//
597// And say I want to set Queen Shao's portrait to all the female players, and my other portrait set to the male characters
598// at level 6. So I would call:
599//
600// ChangePortrait("mysubrace", "my_male_port_", "po_queenshao_", 6);
601//
602// :: You may use this as many times as desired.
603void ChangePortrait(string subrace, string MalePortrait, string FemalePortrait, int Level = 1);
604
605// :: Use to set-up an automated change in the subrace's faction ::
606//
607// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
608// :: FactionCreatureTag: The tag of the creature whose perception of the subrace will be adjusted.
609// :: Reputation: Use any SUBRACE_FACTION_REPUTATION_* constants.
610//
611// Refer to the .PDF Guide book for a detailed example, and implementation of this function.
612//
613// Example of function usage:
614//
615// Say I have a NPC faction called 'Drow Faction'. This faction will normally attack
616// (Hostile) player character. But I want to have the players belonging to the 'Drow' subrace
617// be treated friendly, by the NPCs belonging to this faction...
618//
619// So inorder to do this; first I will need to create:
620// An NPC in a LOCKED room (IE: no player can enter), I would remove all weapons and items from this
621// NPC.
622// Set it as Immortal (NOT Plot).
623// Set it's tag to say: MY_DROW_FACTION_NPC
624// And then call this function:
625//
626// ModifySubraceFaction("drow", "MY_DROW_FACTION_NPC", SUBRACE_FACTION_REPUTATION_FRIENDLY);
627void ModifySubraceFaction(string subrace, string FactionCreatureTag, int Reputation = SUBRACE_FACTION_REPUTATION_HOSTILE);
628
629
630// :: Setup a start location for a subrace ::
631//
632// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
633// :: WaypointTag: The Tag of the waypoint to which the player will be ported to.
634//
635//
636// This will teleport the player belonging to the Subrace 'subrace' to
637// the waypoint, when they enter the module.
638void CreateSubraceStartLocation(string subrace, string WaypointTag);
639
640//3.0.6.4
641
642// :: Setup a death location for a subrace ::
643//
644// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
645// :: WaypointTag: The Tag of the waypoint the player will be teleportd to.
646//
647//
648// This will teleport the player belonging to the Subrace 'subrace' to
649// the waypoint, when they respawn after death.
650void CreateSubraceDeathLocation(string subrace, string WaypointTag);
651
652// 3.0.6.6 - Not just for leto anymore...
653
654// :: Use to setup different skin and hair colors for subrace ::
655//
656// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
657// :: Male_Hair: which color male hair is to be set to.
658// :: Female_Hair: which color female hair is to be set to.
659// :: Male_Skin: which color male skin is to be set to.
660// :: Female_Skin: which color male skin is to be set to.
661// :: Level: the level at which this change is to take place.
662//
663// Written by: TwentyOneScore
664void ModifySubraceAppearanceColors(string subrace, int Male_Hair = -1, int Female_Hair = -1, int Male_Skin = -1, int Female_Skin = -1, int Level = 1);
665
666//3.0.6.6
667
668// :: Use to setup different eye colors for subrace ::
669//
670// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
671// :: Male_Eye: which color male eyes is to be set to.
672// :: Female_Eye: which color female eyes is to be set to.
673// :: use any SSE_EYE_COLOR_* constant
674void SHA_ModifySubraceEyeColors(string subrace, int Male_Eyes = -1, int Female_Eyes = -1, int Level = 1);
675
676//3.0.6.9
677
678// :: Use to setup specific heads for subrace ::
679//
680// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
681// :: Male_Head: which head male is to be set.
682// :: Female_Head: which head female is to be set.
683void ModifySubraceHead(string subrace, int Male_Head = -1, int Female_Head = -1, int Level = 1);
684
685//:: ----- LETO FUNCTION DEFINERS -------
686
687// :: Add/remove a feat to/from the character belonging to a subrace ::
688//
689// >>> NEEDS LETO TO WORK (REFER TO THE MANUAL FOR MORE DETAILS)
690//
691// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
692// :: FeatID: Use any FEAT_* constants.
693// :: Remove: If set to TRUE, it will remove the the feat from the player.
694// :: Level: Level at which to give this bonus feat.
695//
696// NOTE: Player must have the required expansion packs for the feats. IE: If you were to give Epic Dodge,
697// the player must have HoTU expansion pack installed inorder to recieve/use the feat.
698//
699// Example of Usage:
700//
701// Say I want to give Disarm at level 5, and improved knockdown at level 8 to the players belonging to Drow subrace.
702// I also want to remove Alterness from the player at level 10.
703//
704// ModifySubraceFeat("drow", FEAT_DISARM, 5);
705// ModifySubraceFeat("drow", FEAT_IMPROVED_KNOCKDOWN, 8);
706// ModifySubraceFeat("drow", FEAT_ALERTNESS, 10, TRUE);
707//
708//:: You may use this as many times as desired.
709void ModifySubraceFeat(string subrace, int FeatID, int Level = 1, int Remove = FALSE);
710
711
712// :: Create custom base stats::
713//
714// >>> NEEDS LETO TO WORK (REFER TO THE MANUAL FOR MORE DETAILS)
715//
716// :: This is used in conjunction with CreateBaseStatModifier(...) -refer to it for more details.
717//
718// :: --- Fill in the Modifiers as desired.
719// For speed modification use any MOVEMENT_SPEED_* constant.
720//
721// Example: I want to increase Strength by 6, decrease Dexterity by 4, increase Consitution by 4, and change the movement speed to fast.
722// So I would call:
723//
724// struct SubraceBaseStatsModifier MyStats = CustomBaseStatsModifiers(6, -4, 4, 0, 0, 0, MOVEMENT_SPEED_FAST);
725struct SubraceBaseStatsModifier CustomBaseStatsModifiers(int StrengthModifier, int DexterityModifier, int ConstitutionModifier, int IntelligenceModifier, int WisdomModifier, int CharismaModifier, int MovementSpeedModifier);
726
727
728// :: Use to make PERMANENT changes to the ability scores or movement speed of the character::
729//
730// >>> NEEDS LETO TO WORK (REFER TO THE MANUAL FOR MORE DETAILS)
731//
732// :: This is used in conjunction with SubraceBaseStatsModifier CustomBaseStatsModifiers(...)
733//
734// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
735// :: SubraceBaseStatsModifier Stats: Use CustomBaseStatsModifiers(...) to create the stats.
736// :: Level: The level at which to make these changes.
737// :: Set: If you set it to TRUE, then these stats will REPLACE (instead of adding or subtracting) the player's stats.
738//
739//
740// Example of Useage:
741// Say I have a subrace called: black-dragon.
742// And I want to increase Strength by 6, decrease Dexterity by 4, increase Consitution by 4,
743// and decrease charisma by 2, and change the movement speed to fast at level 10.
744//
745// So I would call:
746//
747// struct SubraceBaseStatsModifier MyStats = CustomBaseStatsModifiers(6, -4, 4, 0, 0, -2, MOVEMENT_SPEED_FAST);
748// CreateBaseStatModifier("black-dragon", MyStats, 10);
749//
750// :: You may use this as many times as desired.
751void CreateBaseStatModifier(string subrace, struct SubraceBaseStatsModifier Stats, int Level = 1, int Set = FALSE);
752
753
754// :: Use to the soundset of the character ::
755//
756// >>> NEEDS LETO TO WORK (REFER TO THE MANUAL FOR MORE DETAILS)
757//
758// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
759// :: MaleSoundSet: Refer to the table in the PDF guide book and enter the 'Reference Number'.
760// :: FemaleSoundSet: Refer to the table in the PDF guide book and enter the 'Reference Number'.
761// :: Level: The level at which to change the soundset.
762//
763// Example of Useage:
764// Say I want to change the Male character's soundset to Minotaur, Chief and the Female character's
765// soundset to Succubusat level 16. And then at level 25 change it to Ogre and Nymph.
766// >>> According to the table in the PDF guide book the numbers are 65 for Minotaur Chief, 90 for the Succubus,
767// 70 for Ogre, and 197 for the Nymph soundsets).
768//
769// ChangeSoundSet("mysubrace", 65, 90, 16);
770// ChangeSoundSet("mysubrace", 70, 197, 25);
771//
772// :: You may use this as many times as desired.
773void ChangeSoundSet(string subrace, int MaleSoundSet, int FemaleSoundSet, int Level = 1);
774
775
776// :: Modify a skill a character belonging to a subrace has ::
777//
778// >>> NEEDS LETO TO WORK (REFER TO THE MANUAL FOR MORE DETAILS)
779//
780// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
781// :: SkillID: Use any SKILL_* constants.
782// :: iModifier: The value to increase or decrease or set the skill by/to.
783// :: Set: If set to TRUE, the skill points in the chosen skill will be set to the value of iModifier.
784//
785// Example of Usage:
786//
787// 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.
788// I would call:
789//
790// ModifySubraceSkill("mysubrace", SKILL_SPOT, 15, 10);
791// ModifySubraceSkill("mysubrace", SKILL_SEARCH, -12, 10);
792// ModifySubraceSkill("mysubrace", SKILL_TUMBLE, 5, 16, TRUE);
793void ModifySubraceSkill(string subrace, int SkillID, int iModifier, int Level = 1, int Set = FALSE);
794
795
796// :: Use to setup a special subrace restriction
797//
798// :: subrace: Should be the same as the Subrace's name used in CreateSubrace()
799// :: Type: The type of special restriction (e.g. item, variable etc) See SUBRACE_SPECIAL_RESTRICTION_*
800// :: VarName: The variable name if a variable or the tag if item (etc.)
801// :: Existance: if TRUE then this variable/item must exist, if FALSE it must not exist.
802// :: Database: The name of the database or the tag of the item, which holds the variable (not used for "must have item"-restriction).
803// :: if Database is empty it will default to SUBRACE_DATABASE (if Database) or the Player (if Local var)
804//
805// Written by: Moon
806void CreateSubraceSpecialRestriction(string subrace, int Type, string VarName, int Existance=TRUE, string Database="");
807
808/*
809:::::::::::::::::::::::: Function Definers usuable anywhere ::::::::::::::::::::
810*/
811//:: You may use these functions anywhere, and they would work appropriately.
812
813// ::Erases all "temporary" subracial abilities, so that after respawn or a restoring spell is cast
814// ::the heartbeat script will then reapply the stats again.
815void ReapplySubraceAbilities(object oPC);
816
817//Add this on the Module OnClientEnter script.
818void SubraceOnClientEnter(object oPC = OBJECT_INVALID);
819
820//Add this to Module OnPlayerRespawn script.
821void SubraceOnPlayerRespawn();
822
823//Add this to Module OnPlayerLevelUp script.
824void SubraceOnPlayerLevelUp();
825
826//Add this to Module OnPlayerEquipItem script.
827void SubraceOnPlayerEquipItem();
828
829//Add this to the Module OnItemActivated script.
830void SubraceOnItemActivated();
831
832//Subrace Heartbeat function - For use in default.nss
833void SubraceHeartbeat(object oPC = OBJECT_SELF);
834
835//Add this to the Module OnClientLeave script.
836void SubraceOnClientLeave();
837
838//:: Returns TRUE if SSE has been disabled serverwide.
839//:: This check does NOT care if SSE has been disabled in the current area.
840int GetIsSSEDisabled();
841
842//:: Returns TRUE if SSE has been disabled in Area.
843//:: This check does NOT care if SSE has been disabled Serverwide.
844//:: returns FALSE on error (e.g. if input is non an area)
845int GetIsSSEDisabledInArea(object Area);
846
847//:: Returns SSE_STATUS_OPERATIONAL if SSE is running properly.
848//:: Else it returns a flag depending on the issue.
849//:: See SSE_STATUS_* constants. It adds all that applies.
850//:: If a non-valid area is supplied, area check is skipped.
851int GetSSEStatus(object Area=OBJECT_INVALID);
852
853//:: Force the player to properly un-equip the item.
854void SHA_SubraceForceUnequipItem(object oItem);
855
856//:: Force the player to properly equip oItem in the inventory slot: InvoSlot.
857void SHA_SubraceForceEquipItem(object oItem, int InvoSlot);
858
859//Return the XP modifier for being part of the Subrace
860//(Calclates modifer value for Subrace Favored classes)
861float GetSubraceXPModifier(object oPC);
862
863//:: Returns TRUE if the player is marked as being part of an undead subrace.
864//:: Returns FALSE if player is not an undead OR provided character is NOT a PC!
865//:: (Shayan's Subrace Engine)
866int Subrace_GetIsUndead(object oPC);
867
868//:: Returns the Effective Character level of oPC.
869//:: (Shayan's Subrace Engine)
870int GetECL(object oPC);
871
872//:: Deletes every bit of subracial information stored on the PC. Also destroys equipped skins and claws.
873//:: Set ClearSubraceField to TRUE if you wish, to have their Subrace field cleared (set to "") after this is done.
874//:: 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)
875//:: (Shayan's Subrace Engine)
876void DeleteSubraceInfoOnPC(object oPC, int ClearSubraceField=FALSE);
877
878//:: Change the PC to his/her default humaniod appearance.
879//:: IE: If the player is human and his/her appearance is Illithid, this will turn them back
880//:: to looking like human again.
881//:: (Shayan's Subrace Engine)
882void ChangeToPCDefaultAppearance(object oPC);
883
884
885//:: Returns TRUE if PC belongs to a subrace which is Light sensitive.
886//:: (Shayan's Subrace Engine)
887int GetIsPCLightSensitive(object oPC);
888
889//:: Return the Favored class of the PC. Returns -1 if there is none.
890//:: (Shayan's Subrace Engine)
891int Subrace_GetFavouredClass(object oPC);
892
893//:: Send's a message to PC, with a Subrace Engine title. Set Important to TRUE if
894//:: it is an important message. (Refer to sha_subr_consts for more info.)
895//:: (Shayan's Subrace Engine)
896void SHA_SendSubraceMessageToPC(object oPC, string message, int Important = TRUE);
897
898//:: Send's a message to PC with a Subrace Engine title. This will follow the new
899//:: message standards and allow very selective messages. If you wish to use this
900//:: for non-standard-SSE messages, MessageReference should be MESSAGE_USER_MADE.
901//:: VariableText will then be directly displayed (With Subrace Engine title)
902//::
903//:: MessageType must contain the MESSAGE_TYPE_* constants, for user made messages!
904//::
905//:: NOTE: MESSAGE_TYPE_VITAL will ALWAYS be displayed REGARDLESS of settings and
906//:: MESSAGE_TYPE_LOG will ALWAYS be logged! (Assuming there is a message to send/log)
907//::
908//::
909//:: (Refer to the manual or sha_subr_consts for more info.)
910//:: (Shayan's Subrace Engine)
911void SSE_MessageHandler(object Receiver, int MessageReference, string VariableText="", string VariableText2="", int MessageType = MESSAGE_TYPE_DEFAULT);
912
913//:: Traverses through oPC's inventory, destroying all Skins, and creature items.
914void SearchAndDestroySkinsAndClaws(object oPC);
915
916//:: Removes temporary subrace ability scores and AB boosts.
917void ClearSubraceEffects(object oPC);
918
919//:: Returns TIME_DAY, or TIME_NIGHT depending on the current hour of day.
920int SHA_GetCurrentTime();
921
922//:: Returns the default appearance type of oPC. (It ignores any appearance
923//:: change by SetAppearance()).
924//:: NOTE: oPC must be a player character in order for this to work.
925int SHA_GetDefaultAppearanceType(object oPC);
926
927//:: This will load scripts containing sub-races. You can use the Conditions parameter
928//:: if you want to make the script load only if Leto is (or is not) enabled.
929void LoadSubraceFromScript(string Script, int Conditions=SSE_SUBRACE_LOADER_CONDITION_ALWAYS_LOAD);
930
931// :: Switch oTarget's subrace to Subrace
932// :: Note this function does not do any checking, to see if oTarget meets
933// :: any alignment or race criteria. Should be used with caution.
934// :: Takes approximately 12 - 15 seconds to complete.
935void ApplySubrace(object oTarget, string Subrace);
936
937// :: Use this on the OnModuleLoad script to signal that the subraces has been loaded
938// :: and we are good to go. If you do not call this one, SSE will wait forever!
939// :: It has an internal delay and will wait up 30 seconds for other sub-race scripts to load.
940// :: NOTE! After the first sub-race load has been detected, further 5 seconds are given to finish
941// :: the loading. After that SSE will not wait any further!
942// :: It is adviced to have all your subraces load within 5 seconds of each other!
943// :: (If you use LoadSubraceFromScript(), you do not have to worry about this)
944// ::
945// :: doNWNXInit is used to call the NWNX Init "NWNX!INIT" with parameter "1".
946// :: set to TRUE if you do not have an external call to it and plan on using NWNX (Leto or NWNX database)
947void SSE_ModuleLoadEvent(int doNWNXInit=FALSE);
948
949// :: Use this to get the base race of the alias.
950// :: if Alias is the base race then it returns itself.
951// :: returns "" if the Alias is not valid/no such subrace exist
952// :: if Lowercase is TRUE it will return a lowercased string
953string GetSubraceNameByAlias(string Alias, int Lowercase=FALSE);
954
955// :: Use this to get the race name of the ID.
956// :: returns "" if the Alias is not valid/no such subrace exist
957// :: if Lowercase is TRUE it will return a lowercased string
958string GetSubraceNameByID(int ID, int Lowercase=FALSE);
959
960// :: Returns the Player's Subrace ID.
961int GetPlayerSubraceID(object Player);
962
963//This will add MessageType too the list of message types that is SSE may display
964//If no list is present, a new (empty) list will be created and the type will be added to it.
965//NOTE: Vital will ALWAYS be displayed and Log will ALWAYS be logged!
966void SSE_Message_AddDisplayType(int MessageType);
967
968//This will remove MessageType from the list of message types that is SSE may display
969//If no list is present, it is assumed you want to use the server default without this type!
970//NOTE: Vital will ALWAYS be displayed and Log will ALWAYS be logged!
971void SSE_Message_RemoveDisplayType(int MessageType);
972
973//Creates a new list of the Message types SSE that is allowed to display with MessageType as an entry
974// the old list will be deleted.
975//NOTE: Vital will ALWAYS be displayed and Log will ALWAYS be logged!
976void SSE_Message_SetDisplayType(int MessageType);
977
978//returns the list of message types SSE is allowed to display.
979//if no list is present, MESSAGE_TYPE_SERVER_DEFAULT or FALSE will be returned depending on DoNotReturnServerDefault
980int SSE_Message_GetDisplayType(int DoNotReturnServerDefault=FALSE);
981
982
983//3.0.6
984
985// Adds horse Menu Feat to Hide of oPC
986void SSE_HorseAddHorseMenu(object oPC);
987
988// :: 3.0.6.5
989
990// - Activate Spell-Like Ability
991//
992// oPC : Ability user
993//
994// AbilityUsed : SPELL_*, SPELLABILITY_*, or # from spells.2da
995//
996// oTarget : Ability subject, if not provided oPC is target
997//
998void SubraceAbility(object oPC, int AbilityUsed, object oTarget = OBJECT_SELF);
999
1000// - Replaces subrace value of "" with SUBRACE_*_DEFAULT
1001// if USE_SSE_DEFAULT_RACES = TRUE
1002void CheckAndApplyDefaultSubrace(object oPC);
1003
1004// - Returns oPC's subrace death location Waypoint
1005object GetSubraceDeathWaypoint(object oPC);
1006
1007// - Returns oPC's subrace death location Waypoint
1008object GetSubraceStartWaypoint(object oPC);
1009
1010// - Move oPC to subrace's death location or defaults
1011void Subrace_MoveToDeathLocation(object oPC);
1012
1013//3.0.6.6
1014
1015// Gives oPC it's subraces's hair and/or skin color
1016void ApplySubraceColors(object oPC);
1017
1018// Gives oPC it's subraces's glowing eyes
1019void ApplySubraceEyeColors(object oPC);
1020
1021// Gives oPC glowing eyes, use any SSE_EYE_COLOR_* const
1022void SHA_SetEyeColor(object oPC, int iEyes = -1);
1023
1024//3.0.6.9
1025
1026// Gives oPC it's subraces's head
1027void ApplySubraceHead(object oPC);
1028
1029//
1030//::::::::::::::::::::::::: Interal Function definers:::::::::::::::::::::::::::
1031//
1032// :: Do not use these functions outside this script. They may not work correctly.
1033
1034string SSE_GetStandardMessage(int Ref, string VariableText="", string VariableText2="");
1035void SaveSubraceOnModule(struct Subrace shaSubrace);
1036void GiveSubraceUniqueItem(string SubraceStorage, object oPC);
1037void SaveSubraceAlignmentRestrictionOnModule(struct SubraceAlignmentRestriction shaSubraceAlignRes);
1038void SaveSubraceClassRestrictionOnModule(struct SubraceClassRestriction shaSubraceClassRes);
1039void SaveSubraceSpellResistanceOnModule(struct SubraceSpellResistance shaSubraceSpellRes);
1040void SaveSubraceAppearanceChangeOnModule(struct SubraceDifferentAppearance shaSubraceApp);
1041int CheckIfPCMeetsClassCriteria(object oPC, string SubraceStorage);
1042int CheckIfPCMeetsAlignmentCriteria(object oPC, string SubraceStorage);
1043int CheckIfPCMeetsAnySubraceCriteria(object oPC);
1044int CheckIfPCMeetsSpecialCriteria(object oPC, string SubraceStorage);
1045void SHA_ApplyTemporaryStats(object oPC, string SubraceStorage, int iCurrentTime, int iTime, int AreasReq/*int AreaUndAbove, int AreaIntExt, int AreaNatArt*/);
1046void ApplyTemporarySubraceStats(object oPC, string SubraceStorage, int iCurrentTime, int AreaUndAbove, int AreaIntExt, int AreaNatArt);
1047void ApplyStat_AbilityByPercentage(int AbilityToMod, float percentage, object oPC);
1048void ApplySubraceBonusStatsByPercentage(object oPC, string SubraceStorage);
1049void ApplyAttackBonusByPercentage(float percentage, object oPC);
1050void ApplyArmourClassBonusByPercentage(float percentage, object oPC);
1051void ApplySubraceBonusStatsByPoints(object oPC, string SubraceStorage);
1052void ApplyStat_AbilityByPoints(int AbilityToMod, float points, object oPC);
1053void ApplyAttackBonusByPoints(float points, object oPC);
1054void ApplyTemporarySubraceAppearance(string SubraceStorage, object oPC, int iCurrentTime);
1055void ApplyArmourClassBonusByPoints(float points, object oPC);
1056void ClearSubraceTemporaryStats(object oPC);
1057void LoadSubraceInfoOnPC(object oPC, string subrace);
1058void ApplyPermanentSubraceSpellResistance(int ID, object oPC);
1059void InitiateSubraceChecking(object oPC);
1060int GetFavoredClassExceedsGap(int Race1Favored, int Race2Favored, int Class1, int Class2, int Class3, int Class13Gap, int Class23Gap, int Class12Gap);
1061void ApplySubraceEffect(object oPC, string SubraceStorage, int TimeOfDay);
1062void CheckIfCanUseEquipedWeapon(object oPC);
1063void EquipTemporarySubraceClaw(string SubraceStorage, object oPC, int iTime);
1064void EquipTemporarySubraceSkin(string SubraceStorage, object oPC, int iTime);
1065void CheckAndSwitchSubrace(object oPC);
1066void SubraceCheckItemActivated(object oPC, string sTag);
1067string Subrace_TimeToString(int iTime);
1068int CheckIfPCMeetsPrestigiousClassCriteria(object oPC, string SubraceStorage);
1069int CheckForLetoReLog(object oPC, int Level);
1070string CheckAndModifyBaseStats(object oPC, string SubraceStorage, int Level);
1071string CheckAndModifySkills(object oPC, string SubraceStorage, int Level);
1072string CheckAndModifyFeats(object oPC, string SubraceStorage, int Level);
1073string CheckAndModifySoundSet(object oPC, string SubraceStorage, int Level);
1074void DelayBoot(object oPC);
1075void Subrace_FactionAdjustment(object oPC, string FactionTag, int Adjustment);
1076void ChangeSubraceFactions(object oPC, string SubraceStorage);
1077void Subrace_MoveToStartLocation(object oPC, string subrace = "");
1078void SetSubraceDBInt(string sCampaignName, string sVarName, int nInt, object oPlayer=OBJECT_INVALID);
1079int GetSubraceDBInt(string sCampaignName, string sVarName, object oPlayer=OBJECT_INVALID);
1080void DeleteSubraceDBInt(string sCampaignName, string sVarName, object oPlayer);
1081void DeleteSubraceInfoInDatabase(object oPC, string subrace);
1082void CheckIfCanUseEquippedArmor(object oPC);
1083void ApplyPermanentSubraceAppearance(int ID, object oPC);
1084void ChangeMiscellaneousSubraceStuff(object oPC, int Level);
1085void ModifyAttachments(object oPC, string SubraceStorage, int Level);
1086
1087//Memory handling - Added in 3.0.5
1088
1089int GetSSEInt(string VariableName);
1090void DeleteSSEInt(string VariableName);
1091void SetSSEInt(string VariableName, int Value);
1092int GetSubraceID(string subrace);
1093void SetSubraceID(string subrace, int Value);
1094string GetSubraceStorageLocationByID(int SubraceID);
1095string GetSubraceStorageLocation(string subrace);
1096
1097//::****************************************************************
1098// 1.69 -- Returns TRUE if oSkin is valid and has the Horse Menu Feat on it. Returns FALSE otherwise.
1099int GetSkinHasHorseMenu( object oSkin);
1100//::****************************************************************
1101
1102//:: ---------------------------------------------------------------------------
1103//:: Functions for the Subrace Engine.
1104//:: ---------------------------------------------------------------------------
1105
1106//Data is stored on the module for easy central access.
1107object oStorer = GetModule();
1108
1109/*
1110::::::::::::::::::::::::::: Function definers ::::::::::::::::::::::::::::::::::
1111*/
1112// :: Below lies the list of all the functions useable OnModuleLoad to setup
1113// :: a subrace.
1114
1115//3.0.6.5
1116
1117void SubraceAbility(object oPC,int AbilityUsed,object oTarget = OBJECT_SELF)
1118{
1119 AssignCommand(oPC, ClearAllActions());
1120 if (oTarget == OBJECT_INVALID) oTarget = oPC;
1121 AssignCommand(oPC,ActionCastSpellAtObject(AbilityUsed,oTarget,METAMAGIC_NONE,TRUE,0,PROJECTILE_PATH_TYPE_DEFAULT,TRUE));
1122}
1123
1124object GetSubraceStartWaypoint(object oPC)
1125{
1126 string SubraceStorage = GetSubraceStorageLocation(GetSubRace(oPC));
1127 string WPTag = GetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_START_LOCATION);
1128 object oWP = GetWaypointByTag(WPTag);
1129 return oWP;
1130}
1131
1132object GetSubraceDeathWaypoint(object oPC)
1133{
1134 string SubraceStorage = GetSubraceStorageLocation(GetSubRace(oPC));
1135 string WPTag = GetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_DEATH_LOCATION);
1136 object oWP = GetWaypointByTag(WPTag);
1137 return oWP;
1138}
1139
1140// 3.0.6.4
1141void CreateSubraceDeathLocation(string subrace, string WaypointTag)
1142{
1143 string SubraceStorage = GetSubraceStorageLocation(subrace);
1144 SetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_DEATH_LOCATION, WaypointTag);
1145}
1146
1147//3.0.6
1148void SSE_HorseAddHorseMenu(object oPC)
1149{ // PURPOSE: Add Horse Menu to the PC
1150 object oSkin=SKIN_SupportGetSkin(oPC);
1151 itemproperty iProp;
1152 if (GetIsPC(oPC))
1153 { // valid parameter
1154 iProp=ItemPropertyBonusFeat(40);
1155 AddItemProperty(DURATION_TYPE_PERMANENT,iProp,oSkin);
1156 } // valid parameter
1157} // HorseAddHorseMenu()
1158
1159void NWNX_CreateSubraceDBTables()
1160{
1161 if(ENABLE_NWNX_DATABASE)
1162 {
1163 string sTableName = SUBRACE_DATABASE;
1164
1165 // :: CREATE TABLE " + sTableName + "
1166 // :: (
1167 // :: player varchar(255) not null default '',
1168 // :: tag varchar(255) not null,
1169 // :: name varchar(255) not null,
1170 // :: val text not null default '',
1171 // :: expire int(8) not null default 0,
1172 // :: PRIMARY KEY(player, tag, name)
1173 // :: )
1174 // :: TYPE=InnoDB;
1175 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))";
1176 SQLExecDirect(sSQL);
1177 }
1178}
1179
1180void DeleteSubraceDBInt(string sCampaignName, string sVarName, object oPlayer)
1181{
1182
1183 if(ENABLE_NWNX_DATABASE)
1184 {
1185 if (!GetIsPC(oPlayer))
1186 {
1187 return;
1188 }
1189 string sPlayer = SQLEncodeSpecialChars(GetPCPlayerName(oPlayer));
1190 string sCharName = SQLEncodeSpecialChars(GetStringLowerCase(GetName(oPlayer)));
1191 sVarName = GetStringLowerCase(SQLEncodeSpecialChars(sVarName));
1192 string sSQL = "SELECT val FROM " + sCampaignName + " WHERE player='" + sPlayer +
1193 "' AND tag='" + sCharName + "' AND name='" + sVarName + "'";
1194 SQLExecDirect(sSQL);
1195 //Delete only if exists
1196 if (SQLFetch() == SQL_SUCCESS)
1197 {
1198 sSQL = "DELETE FROM " + sCampaignName + " WHERE player='"+ sPlayer + "' AND tag='" + sCharName + "' AND name='" + sVarName + "'";
1199 SQLExecDirect(sSQL);
1200 }
1201
1202 }
1203 else
1204 {
1205 //Delete only if exists
1206 if(GetCampaignInt(sCampaignName, sVarName, oPlayer) )
1207 {
1208 DeleteCampaignVariable(sCampaignName, sVarName, oPlayer);
1209 }
1210 }
1211
1212}
1213
1214void SetSubraceDBInt(string sCampaignName, string sVarName, int nInt, object oPlayer=OBJECT_INVALID)
1215{
1216 if(ENABLE_NWNX_DATABASE)
1217 {
1218 if (!GetIsPC(oPlayer))
1219 {
1220 return;
1221 }
1222 string sPlayer = SQLEncodeSpecialChars(GetPCPlayerName(oPlayer));
1223 string sCharName = SQLEncodeSpecialChars(GetStringLowerCase(GetName(oPlayer)));
1224 string sVal = IntToString(nInt);
1225 sVarName = GetStringLowerCase(SQLEncodeSpecialChars(sVarName));
1226 string sSQL = "SELECT val FROM " + sCampaignName + " WHERE player='" + sPlayer +
1227 "' AND tag='" + sCharName + "' AND name='" + sVarName + "'";
1228 SQLExecDirect(sSQL);
1229
1230 if (SQLFetch() == SQL_SUCCESS)
1231 {
1232 sSQL = "UPDATE " + sCampaignName + " SET val='" + sVal + "' WHERE player='"+ sPlayer + "' AND tag='" + sCharName + "' AND name='" + sVarName + "'";
1233 SQLExecDirect(sSQL);
1234 }
1235 else
1236 {
1237 sSQL = "INSERT INTO " + sCampaignName + "(player,tag,name,val) VALUES ('" + sPlayer + "','" + sCharName + "','" + sVarName + "','" + sVal + "')";
1238 SQLExecDirect(sSQL);
1239 }
1240
1241 }
1242 else
1243 {
1244 SetCampaignInt(sCampaignName, sVarName, nInt, oPlayer);
1245 }
1246
1247}
1248
1249int GetSubraceDBInt(string sCampaignName, string sVarName, object oPlayer=OBJECT_INVALID)
1250{
1251 int iInt;
1252
1253 if(ENABLE_NWNX_DATABASE)
1254 {
1255 if (!GetIsPC(oPlayer))
1256 {
1257 return 0;
1258 }
1259 string sPlayer = SQLEncodeSpecialChars(GetPCPlayerName(oPlayer));
1260 string sCharName = SQLEncodeSpecialChars(GetStringLowerCase(GetName(oPlayer)));
1261 sVarName = GetStringLowerCase(SQLEncodeSpecialChars(sVarName));
1262
1263 string sSQL = "SELECT val FROM " + sCampaignName + " WHERE player='" + sPlayer + "' AND tag='" + sCharName + "' AND name='" + sVarName + "'";
1264 SQLExecDirect(sSQL);
1265 if (SQLFirstRow() == SQL_SUCCESS)
1266 {
1267 return StringToInt(SQLGetData(1));
1268 }
1269 else
1270 {
1271 return 0;
1272 }
1273 }
1274 else
1275 {
1276 iInt = GetCampaignInt(sCampaignName, sVarName, oPlayer);
1277 }
1278 return iInt;
1279}
1280
1281
1282void 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)
1283{
1284 struct Subrace shaSubrace;
1285
1286 shaSubrace.BaseRace = Race;
1287 shaSubrace.Name = subrace;
1288 shaSubrace.SkinResRef = HideResRef;
1289 shaSubrace.UniqueItemResRef = UniqueItemResRef;
1290 shaSubrace.IsLightSensitive = IsLightSensitive;
1291 shaSubrace.DamageTakenWhileInLight = DamageTakenWhileInLight;
1292 shaSubrace.IsUndergroundSensitive = IsUndergroundSensitive;
1293 shaSubrace.DamageTakenWhileInUnderground = DamageTakenWhileInUnderground;
1294 shaSubrace.ECL = ECL;
1295 shaSubrace.IsUndead = IsUndead;
1296 shaSubrace.PrestigiousSubrace = PrestigiousSubrace;
1297
1298 SaveSubraceOnModule(shaSubrace);
1299}
1300
1301//3.0.6.7
1302void 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)
1303{
1304 string SubraceStorage = GetSubraceStorageLocation(subrace);
1305 int restri = FLAG1 | (CanBeAlignment_Good?FLAG2:0) | (CanBeAlignment_Neutral1?FLAG3:0) | (CanBeAlignment_Evil?FLAG4:0);
1306 restri |= (CanBeAlignment_Lawful?FLAG5:0) | (CanBeAlignment_Neutral2?FLAG6:0) | (CanBeAlignment_Chaotic?FLAG7:0);
1307 SetSSEInt(SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, restri);
1308}
1309
1310
1311//3.0.6.7
1312void 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)
1313{
1314 string SubraceStorage = GetSubraceStorageLocation(subrace);
1315 int restri = FLAG1 | (CanBe_Barbarian?FLAG2:0) | (CanBe_Bard?FLAG3:0) | (CanBe_Cleric?FLAG4:0);
1316 restri |= (CanBe_Druid?FLAG5:0) | (CanBe_Fighter?FLAG6:0) | (CanBe_Monk?FLAG7:0);
1317 restri |= (CanBe_Paladin?FLAG8:0) | (CanBe_Ranger?FLAG9:0) | (CanBe_Rogue?FLAG10:0);
1318 restri |= (CanBe_Sorcerer?FLAG11:0) | (CanBe_Wizard?FLAG12:0);
1319 SetSSEInt(SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, restri);
1320}
1321
1322//3.0.6.7
1323void CreateSubraceGenderRestriction(string subrace, int CanBeMale = TRUE, int CanBeFemale = TRUE)
1324{
1325 string SubraceStorage = GetSubraceStorageLocation(subrace);
1326 int GenderFlag = (CanBeMale?0:FLAG2) | (CanBeFemale?0:FLAG1);
1327 SetSSEInt(SubraceStorage + "_" + SUBRACE_GENDER_RES, GenderFlag);
1328}
1329
1330void CreateSubraceSpellResistance(string subrace, int SpellResistanceBase, int SpellResistanceMax)
1331{
1332 struct SubraceSpellResistance shaSubraceSpellRes;
1333 shaSubraceSpellRes.subrace = subrace;
1334 shaSubraceSpellRes.SpellResistanceBase = SpellResistanceBase;
1335 shaSubraceSpellRes.SpellResistanceMax = SpellResistanceMax;
1336 SaveSubraceSpellResistanceOnModule(shaSubraceSpellRes);
1337}
1338
1339void CreateSubraceAppearance(string subrace, int AppearanceChangeTime, int MaleAppearance, int FemaleAppearance, int Level = 1)
1340{
1341 struct SubraceDifferentAppearance shaSubraceApp;
1342 if(AppearanceChangeTime == TIME_SPECIAL_APPEARANCE_SUBRACE)
1343 {
1344 AppearanceChangeTime = TIME_NONE;
1345 }
1346 shaSubraceApp.subrace = subrace;
1347 shaSubraceApp.ChangeAppearanceTime = AppearanceChangeTime;
1348 shaSubraceApp.MaleAppearance = MaleAppearance;
1349 shaSubraceApp.FemaleAppearance = FemaleAppearance;
1350 shaSubraceApp.Level = Level;
1351 SaveSubraceAppearanceChangeOnModule(shaSubraceApp);
1352}
1353
1354void AddAdditionalBaseRaceToSubrace(string subrace, int AdditionalBaseRace)
1355{
1356 string SubraceStorage = GetSubraceStorageLocation(subrace);
1357 int Flag = NOFLAGS;
1358 switch(AdditionalBaseRace)
1359 {
1360 case RACIAL_TYPE_DWARF: Flag = FLAG1; break;
1361 case RACIAL_TYPE_ELF: Flag = FLAG2; break;
1362 case RACIAL_TYPE_GNOME: Flag = FLAG3; break;
1363 case RACIAL_TYPE_HALFELF: Flag = FLAG4; break;
1364 case RACIAL_TYPE_HALFLING: Flag = FLAG5; break;
1365 case RACIAL_TYPE_HALFORC: Flag = FLAG6; break;
1366 case RACIAL_TYPE_HUMAN: Flag = FLAG7; break;
1367 case RACIAL_TYPE_ALL: Flag = ALLFLAGS; break;
1368 default: Flag = NOFLAGS; break;
1369 }
1370 SetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_RACE, Flag, SUBRACE_BASE_RACE_FLAGS);
1371}
1372
1373int GetIsSSEDisabledInArea(object Area=OBJECT_SELF)
1374{
1375if(!GetIsObjectValid(Area)) return FALSE;
1376return GetLocalInt(Area, "DISABLE_SUBRACE_ENGINE");
1377}
1378
1379int GetIsSSEDisabled()
1380{
1381return GetSSEInt("SHUTDOWN_SSE");
1382}
1383
1384int GetSSEStatus(object Area=OBJECT_INVALID)
1385{
1386int Value = SSE_STATUS_OPERATIONAL;
1387int StatusArea = GetIsSSEDisabledInArea(Area)?SSE_STATUS_DISABLED_IN_AREA:SSE_STATUS_OPERATIONAL;
1388int ServerSetting = GetIsSSEDisabled()?SSE_STATUS_DISABLED_IN_AREA:SSE_STATUS_OPERATIONAL;
1389Value = StatusArea | ServerSetting;
1390return Value;
1391}
1392
1393void SetupSubraceAlias(string subrace, string Alias)
1394{
1395 //Check if sub-race already exists.
1396 if(GetSubraceID(Alias))
1397 {
1398 string Log="*Subrace Engine: Sub-race alias: ";
1399 string trueName=GetSubraceNameByAlias(Alias);
1400 Log+="ERROR\nAttempting to create sub-race alias [" + Alias + "] failed: Similar named sub-race ["+trueName+"] already exists";
1401 WriteTimestampedLogEntry(Log);
1402 return;
1403 }
1404
1405 int ID = GetSubraceID(subrace);
1406 if(!ID)
1407 {
1408 string Log="*Subrace Engine: Sub-race alias: ";
1409 Log+="ERROR\nAttempting to create sub-race alias [" + Alias + "] for ["+subrace+"] failed: No sub-race with that name exists.";
1410 WriteTimestampedLogEntry(Log);
1411 return;
1412 }
1413 SetSubraceID(Alias, ID);
1414 if(SSE_TREAT_ALIAS_AS_SUBRACE & 2)
1415 {
1416 string SubraceStorage = GetSubraceStorageLocationByID(ID);
1417 int Num = GetSSEInt(SubraceStorage + "_ALIAS");
1418 Num++;
1419 SetLocalString(oStorer, SubraceStorage + "_ALIAS_" + IntToString(Num), Alias);
1420 SetSSEInt(SubraceStorage + "_ALIAS", Num);
1421 }
1422}
1423
1424void AddSubraceEffect(string subrace, int EffectID, int Value1, int Value2, int nDurationType, float fDuration, int TimeOfDay)
1425{
1426 string SubraceStorage = GetSubraceStorageLocation(subrace);
1427 int Count = GetSSEInt(SubraceStorage + "_" + SUBRACE_EFFECT_COUNT);
1428 Count++;
1429 SetSSEInt(SubraceStorage + "_" + SUBRACE_EFFECT_COUNT, Count);
1430 SubraceStorage = SubraceStorage + IntToString(Count);
1431 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_EFFECT, EffectID, SUBRACE_EFFECT_FLAGSET);
1432 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_EFFECT, Value1, SUBRACE_EFFECT_VALUE1_FLAGSET);
1433 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_EFFECT, Value2, SUBRACE_EFFECT_VALUE2_FLAGSET);
1434 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_EFFECT, TimeOfDay, SUBRACE_EFFECT_TIME_FLAGSET);
1435 SetSSEInt(SubraceStorage + "_" + SUBRACE_EFFECT_DURATION_TYPE, nDurationType);
1436 SetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_EFFECT_DURATION, fDuration);
1437}
1438
1439void AddSubraceFavoredClass(string subrace, int MaleFavoredClass, int FamaleFavoredClass)
1440{
1441 string SubraceStorage = GetSubraceStorageLocation(subrace);
1442 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_FAVORED_CLASS, MaleFavoredClass + 1, SUBRACE_FAVORED_CLASS_MALE_FLAG);
1443 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_FAVORED_CLASS, FamaleFavoredClass + 1, SUBRACE_FAVORED_CLASS_FEMALE_FLAG);
1444}
1445
1446void CreateSubraceSpecialRestriction(string subrace, int Type, string VarName, int Existance=TRUE, string Database="")
1447{
1448 string SubraceStorage = GetSubraceStorageLocation(subrace);
1449 int Count = GetSSEInt(SubraceStorage + "_" + SUBRACE_SPECIAL_RESTRICTION);
1450 Count++;
1451 SetSSEInt(SubraceStorage + "_" + SUBRACE_SPECIAL_RESTRICTION, Count);
1452
1453 SubraceStorage = SubraceStorage +"_"+SUBRACE_SPECIAL_RESTRICTION+IntToString(Count);
1454
1455 SetSSEInt(SubraceStorage, Type | Existance);
1456 SetLocalString(oStorer, SubraceStorage + SUBRACE_SPECIAL_RESTRICTION_VARNAME, VarName);
1457 if(Database!="" && Database!=SUBRACE_DATABASE)
1458 SetLocalString(oStorer, SubraceStorage + SUBRACE_SPECIAL_RESTRICTION_DATABASE, Database);
1459}
1460
1461//3.0.6.7
1462
1463void 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)
1464{
1465 string SubraceStorage = GetSubraceStorageLocation(subrace);
1466 int restri = FLAG1 | (CanBe_ArcaneArcher?FLAG2:0) | (CanBe_Assasin?FLAG3:0) | (CanBe_Blackguard?FLAG4:0);
1467 restri |= (CanBe_ChampionOfTorm?FLAG5:0) | (CanBe_RedDragonDisciple?FLAG6:0) | (CanBe_DwarvenDefender?FLAG7:0);
1468 restri |= (CanBe_PaleMaster?FLAG8:0) | (CanBe_ShadowDancer?FLAG9:0) | (CanBe_Shifter?FLAG10:0);
1469 restri |= (CanBe_WeaponMaster?FLAG11:0) | (CanBe_HarperScout?FLAG12:0) | (CanBe_PurpleDragonKnight?FLAG13:0);
1470 SetSSEInt(SubraceStorage + "_" + SUBRACE_PRESTIGIOUS_CLASS_RESTRICTION, restri);
1471}
1472
1473void 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)
1474{
1475 string SubraceStorage = GetSubraceStorageLocation(subrace);
1476
1477 int iTime = TimeToApply | GetSSEInt(SubraceStorage + "_" + SUBRACE_STAT_MODIFIERS);
1478 SetSSEInt(SubraceStorage + "_" + SUBRACE_STAT_MODIFIERS, iTime);
1479
1480 int ModType = Stats.ModType;
1481 float StrengthModifier = Stats.StrengthModifier;
1482 float DexterityModifier = Stats.DexterityModifier;
1483 float ConstitutionModifier = Stats.ConstitutionModifier;
1484 float IntelligenceModifier = Stats.IntelligenceModifier;
1485 float WisdomModifier = Stats.WisdomModifier;
1486 float CharismaModifier = Stats.CharismaModifier;
1487 float ACModifier = Stats.ACModifier;
1488 float ABModifier = Stats.ABModifier;
1489
1490 SubraceStorage = SubraceStorage + IntToString(TimeToApply);
1491
1492 SetSSEInt(SubraceStorage + "_" + SUBRACE_STAT_MODIFIER_TYPE, ModType);
1493 //Flags
1494 SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_STAT_MODIFIERS, FLAG4, InInteriorArea);
1495 SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_STAT_MODIFIERS, FLAG5, InExteriorArea);
1496 SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_STAT_MODIFIERS, FLAG6, InArtifacialArea);
1497 SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_STAT_MODIFIERS, FLAG7, InNaturalArea);
1498 SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_STAT_MODIFIERS, FLAG8, InAbovegroundArea);
1499 SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_STAT_MODIFIERS, FLAG9, InUndergroundArea);
1500 SetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_STAT_STR_MODIFIER, StrengthModifier);
1501 SetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_STAT_DEX_MODIFIER, DexterityModifier);
1502 SetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_STAT_CON_MODIFIER, ConstitutionModifier);
1503 SetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_STAT_WIS_MODIFIER, WisdomModifier);
1504 SetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_STAT_INT_MODIFIER, IntelligenceModifier);
1505 SetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_STAT_CHA_MODIFIER, CharismaModifier);
1506 SetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_STAT_AB_MODIFIER, ABModifier);
1507 SetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_STAT_AC_MODIFIER, ACModifier);
1508 SetSSEInt(SubraceStorage + "_" + SUBRACE_HAS_DAY_NIGHT_EFFECTS, TRUE);
1509}
1510
1511
1512//For StatModiferType use only SUBRACE_STAT_MODIFIER_TYPE_PERCENTAGE or SUBRACE_STAT_MODIFIER_TYPE_POINTS
1513struct SubraceStats CreateCustomStats(int StatModifierType, float StrengthModifier, float DexterityModifier, float ConstitutionModifier, float IntelligenceModifier, float WisdomModifier, float CharismaModifier, float ACModifier, float ABModifier)
1514{
1515 struct SubraceStats Stats;
1516 Stats.ModType = StatModifierType;
1517 Stats.StrengthModifier = StrengthModifier;
1518 Stats.DexterityModifier = DexterityModifier;
1519 Stats.ConstitutionModifier = ConstitutionModifier;
1520 Stats.IntelligenceModifier = IntelligenceModifier;
1521 Stats.WisdomModifier = WisdomModifier;
1522 Stats.CharismaModifier = CharismaModifier;
1523 Stats.ACModifier = ACModifier;
1524 Stats.ABModifier = ABModifier;
1525 return Stats;
1526}
1527
1528
1529void SubraceRestrictUseOfItems(string subrace, int ItemType, int TimeOfDay = TIME_BOTH, int Allow = ITEM_TYPE_REQ_DO_NOT_ALLOW)
1530{
1531
1532 string SubraceStorage = GetSubraceStorageLocation(subrace) + "_" + SUBRACE_ITEM_RESTRICTION + "_";
1533 int Set = ItemType;
1534 if(! (Allow & ITEM_TYPE_REQ_DO_NOT_ALLOW) )
1535 {
1536 Set = (~Set);
1537 }
1538
1539 if(Allow & ITEM_TYPE_REQ_ALL)
1540 {
1541 Set |= ITEM_TYPE_REQ_ALL;
1542 }
1543 else
1544 {
1545 Set &= (~ITEM_TYPE_REQ_ALL);
1546 }
1547
1548 switch(TimeOfDay)
1549 {
1550 case TIME_NONE:
1551 //We no use TIME_NONE here, mon. Da i-da-ot mean subrace-form me thinks!
1552 TimeOfDay = TIME_SPECIAL_APPEARANCE_SUBRACE; //No break mon!
1553 case TIME_NIGHT:
1554 case TIME_DAY:
1555 case TIME_SPECIAL_APPEARANCE_SUBRACE:
1556 case TIME_SPECIAL_APPEARANCE_NORMAL:
1557 SetLocalInt( oStorer, SubraceStorage + IntToString(TimeOfDay), Set);
1558 break;
1559 case TIME_BOTH:
1560 SetLocalInt( oStorer, SubraceStorage + IntToString(TIME_NIGHT), Set);
1561 SetLocalInt( oStorer, SubraceStorage + IntToString(TIME_DAY), Set);
1562 break;
1563 }
1564if(GetSSEInt(SubraceStorage + IntToString(TIME_SPECIAL_APPEARANCE_NORMAL))
1565 && GetSSEInt(SubraceStorage + IntToString(TIME_SPECIAL_APPEARANCE_SUBRACE)) )
1566 {
1567 //Both Appearance forms have restrictions, No time based restrictions.
1568 if(GetSSEInt(SubraceStorage + IntToString(TIME_DAY)))
1569 DeleteSSEInt( SubraceStorage + IntToString(TIME_DAY));
1570 if(GetSSEInt(SubraceStorage + IntToString(TIME_NIGHT)))
1571 DeleteSSEInt( SubraceStorage + IntToString(TIME_NIGHT));
1572 }
1573}
1574
1575void SetupSubraceSwitch(string subrace, string switchSubraceNames, int Level, int MustMeetRequirements = TRUE)
1576{
1577 string SubraceStorage = GetSubraceStorageLocation(subrace);
1578 SetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_SWITCH_NAME + IntToString(Level), switchSubraceNames);
1579 if(MustMeetRequirements)
1580 {
1581 SetSSEInt( SubraceStorage + "_" + SUBRACE_SWITCH_MUST_MEET_REQUIREMENTS + IntToString(Level), TRUE);
1582 }
1583}
1584
1585//:: Internal Functions
1586void SaveSubraceOnModule(struct Subrace shaSubrace)
1587{
1588 string subrace = (SSE_AUTO_FORMAT_SUBRACE_NAMES?CapitalizeString(shaSubrace.Name):shaSubrace.Name);
1589
1590 //Check if sub-race already exists.
1591 if(GetSubraceID(subrace))
1592 {
1593 string Log="*Subrace Engine: Sub-race creation: ";
1594 string trueName=GetSubraceNameByAlias(subrace);
1595 if(GetStringLowerCase(trueName) == GetStringLowerCase(subrace))
1596 {
1597 //Sub-race already exists, die...
1598 Log+="ERROR\nAttempting to create sub-race [" + shaSubrace.Name + "] failed: Sub-race already exists";
1599 WriteTimestampedLogEntry(Log);
1600 return;
1601 }
1602 Log+="WARNING\nSub-race Alias [" + shaSubrace.Name + "] for the sub-race ["+trueName+"] was overriden, when Sub-race ["+subrace+"] was created.";
1603 }
1604
1605 //Save the count, and the name of the subrace.
1606 int iCount = GetSSEInt( MODULE_SUBRACE_COUNT);
1607 iCount++;
1608 SetSubraceID(subrace, iCount);
1609 SetSSEInt( MODULE_SUBRACE_COUNT, iCount);
1610 SetLocalString(oStorer, MODULE_SUBRACE_NUMBER + IntToString(iCount), subrace);
1611
1612 string SubraceStorage = GetSubraceStorageLocation(subrace);
1613
1614
1615 int Flag = NOFLAGS;
1616 switch(shaSubrace.BaseRace)
1617 {
1618 case RACIAL_TYPE_DWARF: Flag = FLAG1; break;
1619 case RACIAL_TYPE_ELF: Flag = FLAG2; break;
1620 case RACIAL_TYPE_GNOME: Flag = FLAG3; break;
1621 case RACIAL_TYPE_HALFELF: Flag = FLAG4; break;
1622 case RACIAL_TYPE_HALFLING: Flag = FLAG5; break;
1623 case RACIAL_TYPE_HALFORC: Flag = FLAG6; break;
1624 case RACIAL_TYPE_HUMAN: Flag = FLAG7; break;
1625 case RACIAL_TYPE_ALL: Flag = ALLFLAGS; break;
1626 default: Flag = NOFLAGS; break;
1627 }
1628 SetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_RACE, Flag, SUBRACE_BASE_RACE_FLAGS);
1629
1630 if(shaSubrace.SkinResRef != "none" && shaSubrace.SkinResRef != "")
1631 {
1632 SetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_SKIN + "_1" + "_" + IntToString(TIME_BOTH), GetStringLowerCase( shaSubrace.SkinResRef ));
1633 }
1634 if(shaSubrace.UniqueItemResRef != "" && shaSubrace.UniqueItemResRef != "none")
1635 {
1636 int SubraceUniqueItemCount = 1;
1637 SetSSEInt( SubraceStorage + "_" + SUBRACE_UNIQUEITEM_COUNT, SubraceUniqueItemCount);
1638 SetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_UNIQUEITEM + "_1",GetStringLowerCase( shaSubrace.UniqueItemResRef ) + "_1");
1639 }
1640 SetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_LIGHT_SENSITIVE, SUBRACE_BASE_INFORMATION_FLAGS, shaSubrace.IsLightSensitive);
1641 SetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_UNDERGROUND_SENSITIVE, SUBRACE_BASE_INFORMATION_FLAGS, shaSubrace.IsUndergroundSensitive);
1642 SetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_UNDEAD, SUBRACE_BASE_INFORMATION_FLAGS, shaSubrace.IsUndead);
1643 SetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_PRESTIGIOUS_SUBRACE, SUBRACE_BASE_INFORMATION_FLAGS, shaSubrace.PrestigiousSubrace);
1644
1645 if(shaSubrace.DamageTakenWhileInLight)
1646 {
1647 SetSSEInt( SubraceStorage + "_" + DAMAGE_AMOUNT_IN_LIGHT, shaSubrace.DamageTakenWhileInLight);
1648 }
1649
1650 if(shaSubrace.DamageTakenWhileInUnderground)
1651 {
1652 SetSSEInt( SubraceStorage + "_" + DAMAGE_AMOUNT_IN_UNDERGROUND, shaSubrace.DamageTakenWhileInUnderground);
1653 }
1654 if(shaSubrace.ECL)
1655 {
1656 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, shaSubrace.ECL, SUBRACE_BASE_INFORMATION_ECL);
1657 }
1658
1659 if(shaSubrace.DamageTakenWhileInUnderground || shaSubrace.DamageTakenWhileInLight || shaSubrace.IsLightSensitive || shaSubrace.IsUndergroundSensitive)
1660 {
1661 SetSSEInt( SubraceStorage + "_" + SUBRACE_HAS_DAY_NIGHT_EFFECTS, TRUE);
1662 }
1663}
1664
1665//3.0.6.7
1666
1667void SaveSubraceAlignmentRestrictionOnModule(struct SubraceAlignmentRestriction shaSubraceAlignRes)
1668{
1669 string SubraceStorage = GetSubraceStorageLocation(shaSubraceAlignRes.subrace);
1670 int restri = FLAG1 | (shaSubraceAlignRes.CanBeAlignment_Good?FLAG2:0) | (shaSubraceAlignRes.CanBeAlignment_Neutral1?FLAG3:0) | (shaSubraceAlignRes.CanBeAlignment_Evil?FLAG4:0);
1671 restri |= (shaSubraceAlignRes.CanBeAlignment_Lawful?FLAG5:0) | (shaSubraceAlignRes.CanBeAlignment_Neutral2?FLAG6:0) | (shaSubraceAlignRes.CanBeAlignment_Chaotic?FLAG7:0);
1672 SetSSEInt(SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, restri);
1673/*
1674 string SubraceStorage = GetSubraceStorageLocation(shaSubraceAlignRes.subrace);
1675 SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG1, TRUE);
1676 SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG2, shaSubraceAlignRes.CanBeAlignment_Good);
1677 SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG3, shaSubraceAlignRes.CanBeAlignment_Neutral1);
1678 SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG4, shaSubraceAlignRes.CanBeAlignment_Evil);
1679 SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG5, shaSubraceAlignRes.CanBeAlignment_Lawful);
1680 SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG6, shaSubraceAlignRes.CanBeAlignment_Neutral2);
1681 SetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG7, shaSubraceAlignRes.CanBeAlignment_Chaotic);
1682*/
1683}
1684
1685//3.0.6.7
1686
1687void SaveSubraceClassRestrictionOnModule(struct SubraceClassRestriction shaSubraceClassRes)
1688{
1689 string SubraceStorage = GetSubraceStorageLocation(shaSubraceClassRes.subrace);
1690 int restri = FLAG1 | (shaSubraceClassRes.CanBe_Barbarian?FLAG2:0) | (shaSubraceClassRes.CanBe_Bard?FLAG3:0) | (shaSubraceClassRes.CanBe_Cleric?FLAG4:0);
1691 restri |= (shaSubraceClassRes.CanBe_Druid?FLAG5:0) | (shaSubraceClassRes.CanBe_Fighter?FLAG6:0) | (shaSubraceClassRes.CanBe_Monk?FLAG7:0);
1692 restri |= (shaSubraceClassRes.CanBe_Paladin?FLAG8:0) | (shaSubraceClassRes.CanBe_Ranger?FLAG9:0) | (shaSubraceClassRes.CanBe_Rogue?FLAG10:0);
1693 restri |= (shaSubraceClassRes.CanBe_Sorcerer?FLAG11:0) | (shaSubraceClassRes.CanBe_Wizard?FLAG12:0);
1694 SetSSEInt(SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, restri);
1695}
1696
1697void SaveSubraceSpellResistanceOnModule(struct SubraceSpellResistance shaSubraceSpellRes)
1698{
1699 string SubraceStorage = GetSubraceStorageLocation(shaSubraceSpellRes.subrace);
1700
1701 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_SPELL_RESISTANCE, shaSubraceSpellRes.SpellResistanceBase,SUBRACE_SPELL_RESISTANCE_BASE_FLAGS);
1702 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_SPELL_RESISTANCE, shaSubraceSpellRes.SpellResistanceMax, SUBRACE_SPELL_RESISTANCE_MAX_FLAGS);
1703}
1704
1705void SaveSubraceAppearanceChangeOnModule(struct SubraceDifferentAppearance shaSubraceApp)
1706{
1707 string SubraceStorage = GetSubraceStorageLocation(shaSubraceApp.subrace);
1708 SubraceStorage = SubraceStorage + "_" + IntToString(shaSubraceApp.Level);
1709 SetLocalGroupFlag(oStorer, SubraceStorage + "_" + APPEARANCE_CHANGE, shaSubraceApp.ChangeAppearanceTime, TIME_FLAGS);
1710 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + APPEARANCE_TO_CHANGE, shaSubraceApp.MaleAppearance, APPEARANCE_CHANGE_MALE_FLAG);
1711 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + APPEARANCE_TO_CHANGE, shaSubraceApp.FemaleAppearance, APPEARANCE_CHANGE_FEMALE_FLAG);
1712}
1713
1714void AddAdditionalSkinsToSubrace(string subrace, string SkinResRef, int EquipLevel, int iTime = TIME_BOTH)
1715{
1716 string SubraceStorage = GetSubraceStorageLocation(subrace);
1717 SetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_SKIN + "_" + IntToString(EquipLevel) + "_" + IntToString(iTime), GetStringLowerCase( SkinResRef ) );
1718}
1719
1720void AddClawsToSubrace(string subrace, string RightClawResRef, string LeftClawResRef , int EquipLevel, int iTime = TIME_BOTH)
1721{
1722 string SubraceStorage = GetSubraceStorageLocation(subrace);
1723 if(RightClawResRef != "")
1724 {
1725 SetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_RIGHT_CLAW + "_" + IntToString(EquipLevel) + "_" + IntToString(iTime), RightClawResRef);
1726 }
1727 if(LeftClawResRef != "")
1728 {
1729 SetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_LEFT_CLAW + "_" + IntToString(EquipLevel) + "_" + IntToString(iTime), LeftClawResRef);
1730 }
1731}
1732void AddSubraceItem(string subrace, string ItemResRef, int Level = 1)
1733{
1734 string SubraceStorage = GetSubraceStorageLocation(subrace);
1735 int SubraceUniqueItemCount = GetSSEInt( SubraceStorage + "_" + SUBRACE_UNIQUEITEM_COUNT);
1736 SubraceUniqueItemCount++;
1737 SetSSEInt( SubraceStorage + "_" + SUBRACE_UNIQUEITEM_COUNT, SubraceUniqueItemCount);
1738 SetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_UNIQUEITEM + "_" + IntToString(SubraceUniqueItemCount), GetStringLowerCase( ItemResRef ) + "_" + IntToString(Level));
1739}
1740
1741//LETO STUFF
1742struct SubraceBaseStatsModifier CustomBaseStatsModifiers(int StrengthModifier, int DexterityModifier, int ConstitutionModifier, int IntelligenceModifier, int WisdomModifier, int CharismaModifier, int MovementSpeedModifier)
1743{
1744 struct SubraceBaseStatsModifier Stats;
1745 Stats.StrengthModifier = StrengthModifier;
1746 Stats.DexterityModifier = DexterityModifier;
1747 Stats.ConstitutionModifier = ConstitutionModifier;
1748 Stats.IntelligenceModifier = IntelligenceModifier;
1749 Stats.WisdomModifier = WisdomModifier;
1750 Stats.CharismaModifier = CharismaModifier;
1751 Stats.SpdModifier = MovementSpeedModifier;
1752 return Stats;
1753}
1754
1755void CreateBaseStatModifier(string subrace, struct SubraceBaseStatsModifier Stats, int Level = 1, int Set = FALSE)
1756{
1757 string SubraceStorage = GetSubraceStorageLocation(subrace);
1758
1759 int StrengthModifier = Stats.StrengthModifier;
1760 int DexterityModifier = Stats.DexterityModifier;
1761 int ConstitutionModifier = Stats.ConstitutionModifier;
1762 int IntelligenceModifier = Stats.IntelligenceModifier;
1763 int WisdomModifier = Stats.WisdomModifier;
1764 int CharismaModifier = Stats.CharismaModifier;
1765 int SpdModifier = Stats.SpdModifier;
1766
1767 SubraceStorage = SubraceStorage + "_" + IntToString(Level);
1768 SetSSEInt( SubraceStorage + "_" + SUBRACE_HAS_BASE_STAT_MODIFIERS, TRUE);
1769 if(Set)
1770 {
1771 SetSSEInt( SubraceStorage + "_" + SUBRACE_BASE_STAT_MODIFIERS_REPLACE, Set);
1772 }
1773 if(StrengthModifier)
1774 {
1775 SetSSEInt( SubraceStorage + "_" + SUBRACE_BASE_STAT_STR_MODIFIER, StrengthModifier);
1776 }
1777 if(DexterityModifier)
1778 {
1779 SetSSEInt( SubraceStorage + "_" + SUBRACE_BASE_STAT_DEX_MODIFIER, DexterityModifier);
1780 }
1781 if(ConstitutionModifier)
1782 {
1783 SetSSEInt( SubraceStorage + "_" + SUBRACE_BASE_STAT_CON_MODIFIER, ConstitutionModifier);
1784 }
1785 if(WisdomModifier)
1786 {
1787 SetSSEInt( SubraceStorage + "_" + SUBRACE_BASE_STAT_WIS_MODIFIER, WisdomModifier);
1788 }
1789 if(IntelligenceModifier)
1790 {
1791 SetSSEInt( SubraceStorage + "_" + SUBRACE_BASE_STAT_INT_MODIFIER, IntelligenceModifier);
1792 }
1793 if(CharismaModifier)
1794 {
1795 SetSSEInt( SubraceStorage + "_" + SUBRACE_BASE_STAT_CHA_MODIFIER, CharismaModifier);
1796 }
1797 if(SpdModifier)
1798 {
1799 SetSSEInt( SubraceStorage + "_" + SUBRACE_BASE_STAT_SPD_MODIFIER, SpdModifier);
1800 }
1801}
1802
1803void ModifySubraceFaction(string subrace, string FactionCreatureTag, int Reputation = SUBRACE_FACTION_REPUTATION_HOSTILE)
1804{
1805 string SubraceStorage = GetSubraceStorageLocation(subrace);
1806 int Count = GetSSEInt( SubraceStorage + "_" + SUBRACE_FACTION_COUNT);
1807 Count++;
1808 SetSSEInt( SubraceStorage + "_" + SUBRACE_FACTION_COUNT, Count);
1809 SetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_FACTION_CREATURE + "_" + IntToString(Count), FactionCreatureTag);
1810 SetSSEInt( SubraceStorage + "_" + SUBRACE_FACTION_REPUTATION + "_" + IntToString(Count), Reputation);
1811}
1812
1813void CreateSubraceStartLocation(string subrace, string WaypointTag)
1814{
1815 string SubraceStorage = GetSubraceStorageLocation(subrace);
1816 SetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_START_LOCATION, WaypointTag);
1817}
1818
1819void ModifySubraceAppearanceAttachment(string subrace, int Male_Wings = 0, int Female_Wings = 0, int Male_Tail = 0, int Female_Tail = 0, int Level = 1)
1820{
1821 string SubraceStorage = GetSubraceStorageLocation(subrace);
1822 SubraceStorage = SubraceStorage + "_" + IntToString(Level);
1823 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_ATTACHMENT_FLAGS, Male_Wings, SUBRACE_ATTACHMENT_FLAGS_WINGS_MALE);
1824 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_ATTACHMENT_FLAGS, Female_Wings, SUBRACE_ATTACHMENT_FLAGS_WINGS_FEMALE);
1825 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_ATTACHMENT_FLAGS, Male_Tail, SUBRACE_ATTACHMENT_FLAGS_TAIL_MALE);
1826 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_ATTACHMENT_FLAGS, Female_Tail, SUBRACE_ATTACHMENT_FLAGS_TAIL_FEMALE);
1827}
1828
1829void ModifySubraceFeat(string subrace, int FeatID, int Level = 1, int Remove = FALSE)
1830{
1831 string SubraceStorage = GetSubraceStorageLocation(subrace);
1832 SubraceStorage = SubraceStorage + "_" + IntToString(Level);
1833 int FeatCount = GetSSEInt( SubraceStorage + "_" + SUBRACE_BONUS_FEAT_COUNT);
1834 FeatCount++;
1835 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + IntToString(FeatCount) + "_" + SUBRACE_BONUS_FEAT_FLAGS, FeatID, SUBRACE_BONUS_FEAT_FLAG);
1836 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + IntToString(FeatCount) + "_" + SUBRACE_BONUS_FEAT_FLAGS, Remove, SUBRACE_BONUS_FEAT_REMOVE_FLAG);
1837 SetSSEInt( SubraceStorage + "_" + SUBRACE_BONUS_FEAT_COUNT, FeatCount);
1838}
1839
1840void ChangePortrait(string subrace, string MalePortrait, string FemalePortrait, int Level = 1)
1841{
1842 string SubraceStorage = GetSubraceStorageLocation(subrace);
1843 SetLocalString(oStorer, SubraceStorage + "_" + IntToString(Level)+ "_" + SUBRACE_PORTRAIT_MALE, MalePortrait);
1844 SetLocalString(oStorer, SubraceStorage + "_" + IntToString(Level)+ "_" + SUBRACE_PORTRAIT_FEMALE , FemalePortrait);
1845}
1846
1847void ChangeSoundSet(string subrace, int MaleSoundSet, int FemaleSoundSet, int Level = 1)
1848{
1849 string SubraceStorage = GetSubraceStorageLocation(subrace);
1850 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + IntToString(Level)+ "_" + SUBRACE_SOUNDSET_FLAGS, MaleSoundSet, SUBRACE_SOUNDSET_MALE_FLAG);
1851 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + IntToString(Level)+ "_" + SUBRACE_SOUNDSET_FLAGS, FemaleSoundSet, SUBRACE_SOUNDSET_FEMALE_FLAG);
1852}
1853
1854void ModifySubraceSkill(string subrace, int SkillID, int iModifier, int Level = 1, int Set = FALSE)
1855{
1856 string SubraceStorage = GetSubraceStorageLocation(subrace);
1857 SubraceStorage = SubraceStorage + "_" + IntToString(Level);
1858 int SkillCount = GetSSEInt( SubraceStorage + "_" + SUBRACE_BONUS_SKILL_COUNT);
1859 SkillCount++;
1860 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + IntToString(SkillCount) + "_" + SUBRACE_BONUS_SKILL_FLAGS, SkillID, SUBRACE_BONUS_SKILL_FLAG);
1861 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + IntToString(SkillCount) + "_" + SUBRACE_BONUS_SKILL_FLAGS, Set, SUBRACE_BONUS_SKILL_REMOVE_FLAG);
1862 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + IntToString(SkillCount) + "_" + SUBRACE_BONUS_SKILL_FLAGS, iModifier, SUBRACE_BONUS_SKILL_MODIFIER_FLAG);
1863 SetSSEInt( SubraceStorage + "_" + SUBRACE_BONUS_SKILL_COUNT, SkillCount);
1864}
1865
1866
1867void ModifySubraceAppearanceColors(string subrace, int Male_Hair = -1, int Female_Hair = -1, int Male_Skin = -1, int Female_Skin = -1, int Level = 1)
1868{
1869 string SubraceStorage = GetSubraceStorageLocation(subrace);
1870 SubraceStorage = SubraceStorage + "_" + IntToString(Level);
1871//3.0.6.6 negative value omissions fixed
1872 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_COLORS_FLAGS, Male_Hair, SUBRACE_COLORS_FLAGS_HAIR_MALE);
1873 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_COLORS_FLAGS, Female_Hair, SUBRACE_COLORS_FLAGS_HAIR_FEMALE);
1874 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_COLORS_FLAGS, Male_Skin, SUBRACE_COLORS_FLAGS_SKIN_MALE);
1875 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_COLORS_FLAGS, Female_Skin, SUBRACE_COLORS_FLAGS_SKIN_FEMALE);
1876}
1877
1878// 3.0.6.9
1879void ModifySubraceHead(string subrace, int Male_Head = -1, int Female_Head = -1, int Level = 1)
1880{
1881 string SubraceStorage = GetSubraceStorageLocation(subrace);
1882 SubraceStorage = SubraceStorage + "_" + IntToString(Level);
1883 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_HEAD_FLAGS, Male_Head, SUBRACE_HEAD_FLAGS_MALE);
1884 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_HEAD_FLAGS, Female_Head, SUBRACE_HEAD_FLAGS_FEMALE);
1885}
1886
1887// 3.0.6.6
1888// 3.0.6.9.11 renamed
1889void SHA_ModifySubraceEyeColors(string subrace, int Male_Eyes = -1, int Female_Eyes = -1, int Level = 1)
1890{
1891 string SubraceStorage = GetSubraceStorageLocation(subrace);
1892 SubraceStorage = SubraceStorage + "_" + IntToString(Level);
1893 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_EYE_COLORS_FLAGS, Male_Eyes, SUBRACE_EYE_COLORS_FLAGS_MALE);
1894 SetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_EYE_COLORS_FLAGS, Female_Eyes, SUBRACE_EYE_COLORS_FLAGS_FEMALE);
1895}
1896
1897void DelayBoot(object oPC)
1898{
1899 if(GetLocalInt(oPC, "SUBRACE_NEEDS_TO_RELOG"))
1900 {
1901 BootPC(oPC);
1902 }
1903}
1904
1905void SetIsInDarkness(object oPC, int Flag)
1906{
1907 int ID = GetPlayerSubraceID(oPC);
1908 if(!ID) { return; }
1909 string SubraceStorage = GetSubraceStorageLocationByID(ID);
1910 int IsLightSens = GetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_LIGHT_SENSITIVE, SUBRACE_BASE_INFORMATION_FLAGS);
1911 int DmgTakenL = GetSSEInt( SubraceStorage + "_" + DAMAGE_AMOUNT_IN_LIGHT);
1912 if(IsLightSens || DmgTakenL)
1913 {
1914 SetLocalInt(oPC, SUBRACE_IN_SPELL_DARKNESS, Flag);
1915 }
1916}
1917
1918int Subrace_GetIsInDarkness(object oPC)
1919{
1920 return GetLocalInt(oPC, SUBRACE_IN_SPELL_DARKNESS);
1921}
1922
1923void ApplyLightSensitivity(object oPC)
1924{
1925 if(SPELL_DARKNESS_STOPS_LIGHT_SENSITIVITY && Subrace_GetIsInDarkness(oPC))
1926 {
1927 return;
1928 }
1929 if(!GetLocalInt(oPC, "STRUCK_BLIND"))
1930 {
1931 if(APPLY_LIGHT_BLINDNESS)
1932 {
1933 if(FortitudeSave(oPC, LIGHT_SENSITIVE_SAVING_THROW_DC) == 0)
1934 {
1935 ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectBlindness(), oPC, RoundsToSeconds(LIGHT_STRUCK_BLIND_FOR_ROUNDS));
1936 }
1937 SetLocalInt(oPC, "STRUCK_BLIND", TRUE);
1938 DelayCommand(RoundsToSeconds(LIGHT_BLINDNESS_STRIKES_EVERY_ROUND), SetLocalInt(oPC, "STRUCK_BLIND", FALSE));
1939 }
1940 }
1941 if(APPLY_AB_AND_SAVING_THROW_DECREASES_IN_LIGHT && !GetLocalInt(oPC, "STRUCK_LIGHT_DEC"))
1942 {
1943 effect ABDecrease = EffectAttackDecrease(LIGHT_AB_DECREASE, ATTACK_BONUS_ONHAND);
1944 effect ABDecrease1 = EffectAttackDecrease(LIGHT_AB_DECREASE, ATTACK_BONUS_OFFHAND);
1945 effect SaveDecrease = EffectSavingThrowDecrease(SAVING_THROW_ALL, LIGHT_SAVE_DECREASE, SAVING_THROW_TYPE_ALL);
1946 effect Link = EffectLinkEffects(ABDecrease, ABDecrease1);
1947 Link = SupernaturalEffect(EffectLinkEffects(SaveDecrease, Link));
1948 ApplyEffectToObject(DURATION_TYPE_TEMPORARY, Link, oPC, RoundsToSeconds(LIGHT_CAUSES_AB_AND_SAVES_DECREASE_FOR_ROUNDS + 1));
1949 SetLocalInt(oPC, "STRUCK_LIGHT_DEC", TRUE);
1950 DelayCommand(RoundsToSeconds(LIGHT_CAUSES_AB_AND_SAVES_DECREASE_FOR_ROUNDS), SetLocalInt(oPC, "STRUCK_LIGHT_DEC", FALSE));
1951 }
1952}
1953
1954int GetIsPCLightSensitive(object oPC)
1955{
1956 string SubraceStorage = GetSubraceStorageLocationByID(GetPlayerSubraceID(oPC));
1957 return GetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_LIGHT_SENSITIVE, SUBRACE_BASE_INFORMATION_FLAGS);
1958}
1959
1960void ApplyUndergroundSensitivity(object oPC)
1961{
1962 if(!GetLocalInt(oPC, "STRUCK_BLIND_UND"))
1963 {
1964 if(FortitudeSave(oPC, DARK_SENSITIVE_SAVING_THROW_DC) == 0)
1965 {
1966 ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectBlindness(), oPC, DARK_STRUCK_BLIND_FOR_ROUNDS*6.0);
1967 }
1968 SetLocalInt(oPC, "STRUCK_BLIND_UND", TRUE);
1969 DelayCommand(RoundsToSeconds(DARK_BLINDNESS_STRIKES_EVERY_ROUND), SetLocalInt(oPC, "STRUCK_BLIND_UND", FALSE));
1970 }
1971}
1972
1973void SubraceSpontaneouslyCombust(object oPC)
1974{
1975 if(ReflexSave(oPC, SUBRACE_SPONTANEOUSLY_COMBUST_DC) )
1976 { return; }
1977 effect FireDmg = EffectDamage(d8(), DAMAGE_TYPE_FIRE, DAMAGE_POWER_NORMAL);
1978 effect VisEffect = EffectVisualEffect(VFX_IMP_FLAME_S);
1979 effect iLink = EffectLinkEffects(FireDmg, VisEffect);
1980 ApplyEffectToObject(DURATION_TYPE_TEMPORARY, iLink, oPC, 6.0);
1981
1982}
1983
1984void ApplyDamageWhileInLight(object oPC, int DmgTaken)
1985{
1986 if(SPELL_DARKNESS_STOPS_LIGHT_SENSITIVITY && Subrace_GetIsInDarkness(oPC))
1987 {
1988 return;
1989 }
1990 if(!GetLocalInt(oPC, "SB_LGHT_DMGED"))
1991 {
1992 SetLocalInt(oPC, "SB_LGHT_DMGED", TRUE);
1993 effect LightDamage;
1994 if(DmgTaken > 0)
1995 {
1996 LightDamage = EffectDamage(DmgTaken, DAMAGE_TYPE_DIVINE, DAMAGE_POWER_ENERGY);
1997 }
1998 else if(DmgTaken < 0)
1999 {
2000 DmgTaken = abs(DmgTaken);
2001 LightDamage = EffectRegenerate(DmgTaken, 1.0);
2002 }
2003 if(SUBRACE_SPONTANEOUS_COMBUSTION_WHILE_IN_LIGHT)
2004 {
2005 if(d100() <= SUBRACE_SPONTANEOUS_COMBUSTION_PERCENTAGE)
2006 {
2007 int i = 0;
2008 //Combust visual effect.
2009 effect eDur = EffectVisualEffect(498);
2010 ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDur, oPC, RoundsToSeconds(LIGHT_DAMAGES_EVERY_ROUNDS));
2011
2012 while(i != LIGHT_DAMAGES_EVERY_ROUNDS)
2013 {
2014 DelayCommand(RoundsToSeconds(i), SubraceSpontaneouslyCombust(oPC));
2015 i++;
2016 }
2017 }
2018 }
2019 ApplyEffectToObject(DURATION_TYPE_TEMPORARY, LightDamage, oPC, 1.0);
2020 DelayCommand(RoundsToSeconds(LIGHT_DAMAGES_EVERY_ROUNDS), SetLocalInt(oPC,"SB_LGHT_DMGED", FALSE));
2021 }
2022}
2023
2024int GetSubraceID(string subrace)
2025{
2026 return GetSSEInt( SUBRACE_TAG + "_" + GetStringLowerCase(subrace));
2027}
2028
2029void SetSubraceID(string subrace, int Value)
2030{
2031 SetSSEInt( SUBRACE_TAG + "_" + GetStringLowerCase(subrace), Value);
2032}
2033
2034string GetSubraceStorageLocationByID(int SubraceID)
2035{
2036 return SUBRACE_TAG + "_ID_" + IntToHexString(SubraceID);
2037}
2038
2039string GetSubraceStorageLocation(string subrace)
2040{
2041 return GetSubraceStorageLocationByID(GetSubraceID(subrace));
2042}
2043
2044void ApplyDamageWhileInDark(object oPC, int DmgTaken)
2045{
2046 if(!GetLocalInt(oPC, "SB_DARK_DMGED"))
2047 {
2048 SetLocalInt(oPC, "SB_DARK_DMGED", TRUE);
2049 effect DarkDamage;
2050 if(DmgTaken > 0)
2051 {
2052 DarkDamage = EffectDamage(DmgTaken, DAMAGE_TYPE_NEGATIVE, DAMAGE_POWER_ENERGY);
2053 }
2054 else if(DmgTaken < 0)
2055 {
2056 DmgTaken = abs(DmgTaken);
2057 DarkDamage = EffectRegenerate(DmgTaken, 1.0);
2058 }
2059 ApplyEffectToObject(DURATION_TYPE_TEMPORARY, DarkDamage, oPC, 1.0);
2060 DelayCommand(RoundsToSeconds(DARKNESS_DAMAGES_EVERY_ROUNDS), SetLocalInt(oPC,"SB_DARK_DMGED", FALSE));
2061 }
2062}
2063
2064string FlagNumberToErrorMSG(int iError)
2065{
2066 string sReturn = "";
2067 if(iError & SUBRACE_ERROR_UNRECOGNISED)
2068 {
2069 //Exploiting the fact that "unrecognised subrace" never gets any other "errors"
2070 /*sReturn +=*/return "\n-" + SSE_GetStandardMessage(MESSAGE_SUBRACE_UNRECOGNISED);
2071 }
2072 if(iError & SUBRACE_ERROR_ALIGNMENT)
2073 {
2074 sReturn += "\n-" + SSE_GetStandardMessage(MESSAGE_SUBRACE_CRITERIA_ALIGNMENT_FAILED);
2075 }
2076 if(iError & SUBRACE_ERROR_RACE)
2077 {
2078 sReturn += "\n-" + SSE_GetStandardMessage(MESSAGE_SUBRACE_CRITERIA_BASE_RACE_FAILED);
2079 }
2080 if(iError & SUBRACE_ERROR_CLASS)
2081 {
2082 sReturn += "\n-" + SSE_GetStandardMessage(MESSAGE_SUBRACE_CRITERIA_CLASS_FAILED);
2083 }
2084 if(iError & SUBRACE_ERROR_PRESTIGE_FAILURE)
2085 {
2086 sReturn += "\n-" + SSE_GetStandardMessage(MESSAGE_FAILED_TO_MEET_PRESTIGIOUS_CLASS_RESTRICTION);
2087 }
2088 if(iError & SUBRACE_ERROR_PRESTIGE_NOT_MET)
2089 {
2090 sReturn += "\n-" + SSE_GetStandardMessage(MESSAGE_CANNOT_BE_PART_OF_PRESTIGIOUS_SUBRACE);
2091 }
2092 if(iError & SUBRACE_ERROR_GENDER)
2093 {
2094 sReturn += "\n-" + SSE_GetStandardMessage(MESSAGE_SUBRACE_GENDER_FAILED);
2095 }
2096 if(iError & SUBRACE_ERROR_SPECIAL_RESTRICTION)
2097 {
2098 sReturn += "\n-" + SSE_GetStandardMessage(MESSAGE_SUBRACE_CRITERIA_SPECIAL_RESTRICTION_FAILED);
2099 }
2100 return sReturn;
2101}
2102
2103//3.0.6.7
2104int PrestigeClassToFlags(int Class)
2105{
2106int Flag = 0;
2107 switch(Class)
2108 {
2109 case CLASS_TYPE_ARCANE_ARCHER:
2110 Flag = FLAG2;
2111 break;
2112 case CLASS_TYPE_ASSASSIN:
2113 Flag = FLAG3;
2114 break;
2115 case CLASS_TYPE_BLACKGUARD:
2116 Flag = FLAG4;
2117 break;
2118 case CLASS_TYPE_DIVINE_CHAMPION:
2119 Flag = FLAG5;
2120 break;
2121 case CLASS_TYPE_DRAGON_DISCIPLE:
2122 Flag = FLAG6;
2123 break;
2124 case CLASS_TYPE_DWARVEN_DEFENDER:
2125 Flag = FLAG7;
2126 break;
2127 case CLASS_TYPE_HARPER:
2128 Flag = FLAG8;
2129 break;
2130 case CLASS_TYPE_PALE_MASTER:
2131 Flag = FLAG9;
2132 break;
2133 case CLASS_TYPE_SHADOWDANCER:
2134 Flag = FLAG10;
2135 break;
2136 case CLASS_TYPE_SHIFTER:
2137 Flag = FLAG11;
2138 break;
2139 case CLASS_TYPE_WEAPON_MASTER:
2140 Flag = FLAG12;
2141 break;
2142 case CLASS_TYPE_PURPLE_DRAGON_KNIGHT:
2143 Flag = FLAG13;
2144 break;
2145 }
2146return Flag;
2147}
2148
2149int RacialTypeToFlags(int Race)
2150{
2151int Flag = 0;
2152 switch(Race)
2153 {
2154 case RACIAL_TYPE_DWARF:
2155 Flag = FLAG1;
2156 break;
2157 case RACIAL_TYPE_ELF:
2158 Flag = FLAG2;
2159 break;
2160 case RACIAL_TYPE_GNOME:
2161 Flag = FLAG3;
2162 break;
2163 case RACIAL_TYPE_HALFELF:
2164 Flag = FLAG4;
2165 break;
2166 case RACIAL_TYPE_HALFLING:
2167 Flag = FLAG5;
2168 break;
2169 case RACIAL_TYPE_HALFORC:
2170 Flag = FLAG6;
2171 break;
2172 case RACIAL_TYPE_HUMAN:
2173 Flag = FLAG7;
2174 break;
2175 case RACIAL_TYPE_ALL:
2176 Flag = FLAG8;
2177 break;
2178 }
2179return Flag;
2180}
2181
2182int CheckIfPCMeetsBaseRaceCriteria(object oPC, string SubraceStorage)
2183{
2184 int PCRace = GetRacialType(oPC);
2185 int iResult = GetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_BASE_RACE, SUBRACE_BASE_RACE_FLAGS);
2186 return (iResult)?(iResult & RacialTypeToFlags(PCRace)):TRUE;
2187}
2188
2189int CheckIfPCMeetsSpecialCriteria(object oPC, string SubraceStorage)
2190{
2191 SubraceStorage = SubraceStorage +"_"+SUBRACE_SPECIAL_RESTRICTION;
2192 int Count = GetSSEInt( SubraceStorage);
2193 string Test;
2194 int i=1;
2195 int Type, TestValue;
2196 string Varname, Database;
2197 int ReturnValue=TRUE;
2198 for( ; (i<=Count) && ReturnValue ; i++)
2199 {
2200 Test=SubraceStorage+IntToString(i);
2201 Type=GetSSEInt( Test);
2202 Varname=GetLocalString(oStorer, Test + SUBRACE_SPECIAL_RESTRICTION_VARNAME);
2203 Database=GetLocalString(oStorer, Test + SUBRACE_SPECIAL_RESTRICTION_DATABASE);
2204 switch(Type&SUBRACE_SPECIAL_RESTRICTION_TYPE_ALL)
2205 {
2206 case SUBRACE_SPECIAL_RESTRICTION_TYPE_DATABASE:
2207 if(Database=="") Database=SUBRACE_DATABASE;
2208 TestValue=GetSubraceDBInt(Database, Varname, oPC);
2209 break;
2210 case SUBRACE_SPECIAL_RESTRICTION_TYPE_ITEM:
2211 TestValue=GetIsObjectValid(GetItemPossessedBy(oPC, Varname));
2212 break;
2213 case SUBRACE_SPECIAL_RESTRICTION_TYPE_LOCAL_VAR:
2214 {
2215 object Temp;
2216 if(Database!="")
2217 {
2218 Temp = GetItemPossessedBy(oPC, Database);
2219 if(!GetIsObjectValid(Temp))
2220 {
2221 Temp=GetObjectByTag(Database);
2222 if(!GetIsObjectValid(Temp))
2223 {
2224 Temp=oPC;
2225 }
2226 }
2227 }
2228 else Temp=oPC;
2229 TestValue=GetLocalInt(Temp, Varname);
2230 break;
2231 }
2232 }
2233 ReturnValue=( ((Type&1) && TestValue) || (!(Type&1) && !TestValue) );
2234 }
2235 return ReturnValue;
2236}
2237
2238int CheckIfPCMeetsGenderCriteria(object oPC, string SubraceStorage)
2239{
2240 int iFlag = GetSSEInt( SubraceStorage + "_" + SUBRACE_GENDER_RES);
2241 int PCGender = GetGender(oPC);
2242 switch(PCGender)
2243 {
2244 case GENDER_MALE: PCGender = FLAG2; break;
2245 case GENDER_FEMALE: PCGender = FLAG1; break;
2246 default: break;
2247 }
2248 return !(iFlag & PCGender);
2249}
2250int CheckIfPCMeetsClassCriteria(object oPC, string SubraceStorage)
2251{
2252 int PCClass = GetClassByPosition(1, oPC);
2253 int canBeBarbarian = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, FLAG2);
2254 int canBeBard = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, FLAG3);
2255 int canBeCleric = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, FLAG4);
2256 int canBeDruid = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, FLAG5);
2257 int canBeFighter = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, FLAG6);
2258 int canBeMonk = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, FLAG7);
2259 int canBePaladin = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, FLAG8);
2260 int canBeRanger = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, FLAG9);
2261 int canBeRogue = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, FLAG10);
2262 int canBeSorcerer = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, FLAG11);
2263 int canBeWizard = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, FLAG12);
2264 //longest return ever!
2265 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));
2266}
2267
2268int CheckIfPCMeetsPrestigiousClassCriteria(object oPC, string SubraceStorage)
2269{
2270
2271 int MinLevel = GetSSEInt( SubraceStorage + "_" + SUBRACE_PRESTIGIOUS_CLASS_RESTRICTION_MINIMUM_LEVELS);
2272 int iClassType = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_PRESTIGIOUS_CLASS_RESTRICTION,
2273 MEDIUMGROUP1|TINYGROUP3);
2274 int i=2;
2275 int iMatch;
2276 for( ; i < 4; i++)
2277 {
2278 iMatch = PrestigeClassToFlags(GetClassByPosition(i, oPC) );
2279 if(iMatch & iClassType)
2280 {
2281 MinLevel -= GetLevelByPosition(i, oPC);
2282 }
2283 }
2284 //Returns TRUE if MinLevel is less than or equal to 0 (we have the exact or more levels than req.)
2285 return (MinLevel<1);
2286}
2287
2288int CheckIfPCMeetsAlignmentCriteria(object oPC, string SubraceStorage)
2289{
2290 int PCAlign1 = GetAlignmentGoodEvil(oPC);
2291 int PCAlign2 = GetAlignmentLawChaos(oPC);
2292 int align1 = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG2);
2293 int align2 = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG3);
2294 int align3 = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG4);
2295 int align4 = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG5);
2296 int align5 = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG6);
2297 int align6 = GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG7);
2298 return ((PCAlign1 == ALIGNMENT_GOOD && align1) || (PCAlign1 == ALIGNMENT_NEUTRAL && align2) || (PCAlign1 == ALIGNMENT_EVIL && align3))
2299 &&
2300 ((PCAlign2 == ALIGNMENT_LAWFUL && align4) || (PCAlign2 == ALIGNMENT_NEUTRAL && align5) || (PCAlign2 == ALIGNMENT_CHAOTIC && align6));
2301}
2302
2303int CheckIfPCGetsAnyErrorsWithSubraceTest(object oPC, int ID)
2304{
2305 int Error=0;
2306 string SubraceStorage;
2307 //Check if the subrace exists.
2308 if(ID)
2309 {
2310 SubraceStorage = GetSubraceStorageLocationByID(ID);
2311 int IsPrestigious = GetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_PRESTIGIOUS_SUBRACE, SUBRACE_BASE_INFORMATION_FLAGS);
2312 if(IsPrestigious && GetPlayerLevel(oPC) == 1)
2313 {
2314 Error |= SUBRACE_ERROR_PRESTIGE_FAILURE;
2315 }
2316 else if(IsPrestigious)
2317 {
2318 //What (if any) is the Class Restriction
2319 if(GetSSEInt( SubraceStorage + "_" + SUBRACE_PRESTIGIOUS_CLASS_RESTRICTION))
2320 {
2321 if(!CheckIfPCMeetsPrestigiousClassCriteria(oPC, SubraceStorage))
2322 {
2323 Error |=SUBRACE_ERROR_PRESTIGE_NOT_MET;
2324 }
2325 }
2326 }
2327 //Check if we meet Race Req.
2328 if(!CheckIfPCMeetsBaseRaceCriteria(oPC, SubraceStorage))
2329 {
2330 Error |= SUBRACE_ERROR_RACE;
2331 }
2332
2333 if(GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_ALIGNMENT_RESTRICTION, FLAG1))
2334 {
2335 //Check if we meet Alignments Req.
2336 if(!CheckIfPCMeetsAlignmentCriteria(oPC, SubraceStorage))
2337 {
2338 Error |= SUBRACE_ERROR_ALIGNMENT;
2339 }
2340 }
2341 if(GetLocalFlag(oStorer, SubraceStorage + "_" + SUBRACE_CLASS_RESTRICTION, FLAG1))
2342 {
2343 //Check if we meet Class Req.
2344 if(!CheckIfPCMeetsClassCriteria(oPC,SubraceStorage))
2345 {
2346 Error |=SUBRACE_ERROR_CLASS;
2347 }
2348 }
2349 if(GetSSEInt( SubraceStorage + "_" + SUBRACE_GENDER_RES) > 0)
2350 {
2351 if(!CheckIfPCMeetsGenderCriteria(oPC, SubraceStorage))
2352 {
2353 Error |= SUBRACE_ERROR_GENDER;
2354 }
2355 }
2356 if(!CheckIfPCMeetsSpecialCriteria(oPC, SubraceStorage))
2357 {
2358 Error |= SUBRACE_ERROR_SPECIAL_RESTRICTION;
2359 }
2360 } //FAILED TO FIND ANY SUCH SUBRACE
2361 else { Error = SUBRACE_ERROR_UNRECOGNISED; }
2362
2363return Error;
2364}
2365
2366int CheckIfPCMeetsAnySubraceCriteria(object oPC)
2367{
2368 string subrace = GetSubRace(oPC);
2369 int ID = GetSubraceID(subrace);
2370 int Error = CheckIfPCGetsAnyErrorsWithSubraceTest(oPC, ID);
2371 int i=1;
2372 string sErrorMessage;
2373 if((Error & SUBRACE_ERROR_UNRECOGNISED))
2374 {
2375 SSE_MessageHandler(oPC, MESSAGE_SUBRACE_UNRECOGNISED, subrace);
2376 return SUBRACE_UNRECOGNISED;
2377 }
2378 else if(Error > 0)
2379 {
2380 string sMsg = FlagNumberToErrorMSG(Error);
2381 SSE_MessageHandler(oPC, MESSAGE_SUBRACE_CRITERIA_FAILED, sMsg);
2382 SetSubRace(oPC, "");
2383 SSE_MessageHandler(oPC, MESSAGE_SUBRACE_FAILED_CRITERIA_SO_REMOVED);
2384 }
2385 else SSE_MessageHandler(oPC, MESSAGE_SUBRACE_CRITERIA_MET);
2386 return !(Error > 0);
2387}
2388
2389
2390string GetTemporarySubraceSkin(object oPC, string SubraceStorage, int iTime)
2391{
2392 int Level = GetPlayerLevel(oPC);
2393 string SkinResRef;
2394 while(Level > 0)
2395 {
2396 string resref = GetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_SKIN + "_" + IntToString(Level) + "_" + IntToString(iTime));
2397 if(resref != "")
2398 {
2399 SkinResRef = resref;
2400 break;
2401 }
2402 Level--;
2403 }
2404 return SkinResRef;
2405}
2406
2407//::****************************************************************
2408// 1.69 -- Returns TRUE if oSkin is valid and has the Horse Menu Feat on it. Returns FALSE otherwise.
2409int GetSkinHasHorseMenu( object oSkin)
2410{ if( !GetIsObjectValid( oSkin)) return FALSE;
2411
2412 itemproperty ipHorseMenu = GetFirstItemProperty( oSkin);
2413 while( GetIsItemPropertyValid( ipHorseMenu))
2414 { if( (GetItemPropertyType( ipHorseMenu) == ITEM_PROPERTY_BONUS_FEAT) &&
2415 (GetItemPropertySubType( ipHorseMenu) == IP_CONST_HORSE_MENU_SSE))
2416 return TRUE;
2417 ipHorseMenu = GetNextItemProperty( oSkin);
2418 }
2419 return FALSE;
2420}
2421//::****************************************************************
2422
2423void EquipTemporarySubraceSkin(string SubraceStorage, object oPC, int iTime)
2424{
2425 string sSkin = GetTemporarySubraceSkin(oPC, SubraceStorage, iTime);
2426 if(sSkin == "")
2427 {
2428 sSkin = GetTemporarySubraceSkin(oPC, SubraceStorage, TIME_BOTH);
2429 }
2430 object ExistingSkin = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oPC);
2431 string ResrefExistingSkin = GetResRef(ExistingSkin);
2432 if(ResrefExistingSkin != sSkin)
2433 {
2434 object NewSkin = CreateItemOnObject(sSkin, oPC);
2435
2436 //::****************************************************************
2437 // 1.69 -- Add horse menu to new skin if needed
2438 if( (GetIsPC( oPC) || GetIsDM( oPC)) && !GetSkinHasHorseMenu( NewSkin) &&
2439 ((!GetIsObjectValid( ExistingSkin) && !GetHasFeat( FEAT_HORSE_MENU, oPC)) ||
2440 GetSkinHasHorseMenu( ExistingSkin)) )
2441 { itemproperty iProp = ItemPropertyBonusFeat( IP_CONST_HORSE_MENU_SSE);
2442 AddItemProperty( DURATION_TYPE_PERMANENT, iProp, NewSkin);
2443 }
2444 //::****************************************************************
2445
2446 if(GetIsObjectValid(ExistingSkin))
2447 {
2448 SetPlotFlag(ExistingSkin, FALSE);
2449 DestroyObject(ExistingSkin, 0.2*SSE_LOAD_FACTOR);
2450 }
2451 SetIdentified(NewSkin, TRUE);
2452 DelayCommand(1.0*SSE_LOAD_FACTOR, AssignCommand(oPC, SHA_SubraceForceEquipItem(NewSkin, INVENTORY_SLOT_CARMOUR)));
2453 }
2454}
2455
2456string GetTemporarySubraceClaw(object oPC, string SubraceStorage, string Claw, int iTime)
2457{
2458 int Level = GetPlayerLevel(oPC);
2459 string ClawResRef = "";
2460 while(Level > 0)
2461 {
2462 string resref = GetLocalString(oStorer, SubraceStorage + "_" + Claw + "_" + IntToString(Level) + "_" + IntToString(iTime));
2463 if(resref != "")
2464 {
2465 ClawResRef = resref;
2466 break;
2467 }
2468 Level--;
2469 }
2470 return ClawResRef;
2471}
2472
2473
2474void EquipTemporarySubraceClaw(string SubraceStorage, object oPC, int iTime)
2475{
2476 string sLeftClaw = GetTemporarySubraceClaw(oPC, SubraceStorage, SUBRACE_LEFT_CLAW, iTime);
2477 string sRightClaw = GetTemporarySubraceClaw(oPC, SubraceStorage, SUBRACE_RIGHT_CLAW, iTime);
2478
2479 if(sLeftClaw == "")
2480 {
2481 sLeftClaw = GetTemporarySubraceClaw(oPC, SubraceStorage, SUBRACE_LEFT_CLAW, TIME_BOTH);
2482 }
2483 if(sRightClaw == "")
2484 {
2485 sRightClaw = GetTemporarySubraceClaw(oPC, SubraceStorage, SUBRACE_RIGHT_CLAW, TIME_BOTH);
2486 }
2487 object ExistingLeftClaw = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oPC);
2488 object ExistingRightClaw = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oPC);
2489 string ResrefExistingLClaw = GetStringLowerCase(GetResRef(ExistingLeftClaw));
2490 string ResrefExistingRClaw = GetStringLowerCase(GetResRef(ExistingRightClaw));
2491 if((ResrefExistingRClaw != sRightClaw) || (ResrefExistingLClaw != sLeftClaw))
2492 {
2493 SSE_MessageHandler(oPC, MESSAGE_SUBRACE_CLAWS_WAIT_FOR_CLAWS_EQUIPPING);
2494 if(!GetHasFeat(FEAT_WEAPON_PROFICIENCY_CREATURE, oPC))
2495 {
2496 SSE_MessageHandler(oPC, MESSAGE_SUBRACE_CLAWS_MISSING_CREATURE_WEAPON_PROFICIENCY);
2497 return;
2498 }
2499 DelayCommand(9.0*SSE_LOAD_FACTOR, SSE_MessageHandler(oPC,MESSAGE_SUBRACE_CLAWS_SUCCESSFULLY_EQUIPPED));
2500 }
2501 if(ResrefExistingRClaw != sRightClaw)
2502 {
2503 object NewRClaw = CreateItemOnObject(sRightClaw, oPC);
2504 if(sRightClaw == "none" || GetIsObjectValid(ExistingRightClaw))
2505 {
2506 SetPlotFlag(ExistingRightClaw, FALSE);
2507 DestroyObject(ExistingRightClaw, 0.2*SSE_LOAD_FACTOR);
2508 }
2509 SetIdentified(NewRClaw, TRUE);
2510 DelayCommand(1.0*SSE_LOAD_FACTOR, AssignCommand(oPC, SHA_SubraceForceEquipItem(NewRClaw, INVENTORY_SLOT_CWEAPON_R)));
2511 }
2512 if(ResrefExistingLClaw != sLeftClaw)
2513 {
2514 object NewLClaw = CreateItemOnObject(sLeftClaw, oPC);
2515 if(sLeftClaw == "none" || GetIsObjectValid(ExistingLeftClaw))
2516 {
2517 SetPlotFlag(ExistingLeftClaw, FALSE);
2518 DestroyObject(ExistingLeftClaw, 0.3*SSE_LOAD_FACTOR);
2519 }
2520 SetIdentified(NewLClaw, TRUE);
2521 DelayCommand(5.0*SSE_LOAD_FACTOR, AssignCommand(oPC, SHA_SubraceForceEquipItem(NewLClaw, INVENTORY_SLOT_CWEAPON_L)));
2522 }
2523}
2524
2525void SearchAndDestroySkinsAndClaws(object oPC)
2526{
2527 object oItem = GetFirstItemInInventory(oPC);
2528 while(GetIsObjectValid(oItem))
2529 {
2530 int iType = GetBaseItemType(oItem);
2531 if(iType == BASE_ITEM_CREATUREITEM || iType == BASE_ITEM_CPIERCWEAPON || iType == BASE_ITEM_CSLASHWEAPON || iType == BASE_ITEM_CSLSHPRCWEAP)
2532 {
2533 SetPlotFlag(oItem, FALSE);
2534 DestroyObject(oItem, 0.1);
2535 }
2536 oItem = GetNextItemInInventory(oPC);
2537 }
2538
2539
2540}
2541
2542void GiveSubraceUniqueItem(string SubraceStorage, object oPC)
2543{
2544 int i = 0;
2545 int iLevel = GetPlayerLevel(oPC);
2546 int iChk = GetSubraceDBInt(SUBRACE_DATABASE, SubraceStorage + "_" + SUBRACE_UNIQUEITEM, oPC);
2547 if(iChk > iLevel)
2548 { return; }
2549 i = iChk;
2550 int SubraceUniqueItemCount = GetSSEInt( SubraceStorage + "_" + SUBRACE_UNIQUEITEM_COUNT);
2551 while(i <= SubraceUniqueItemCount)
2552 {
2553 i++;
2554 string resref = GetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_UNIQUEITEM + "_" + IntToString(i));
2555 if(resref != "")
2556 {
2557 string sLevel = GetStringRight(resref, 2);
2558 if(GetStringLeft(sLevel, 1) == "_")
2559 {
2560 //resref: itemref_1
2561 sLevel = GetStringRight(sLevel, 1);
2562 resref = GetStringLeft(resref, GetStringLength(resref) - 2);
2563 }
2564 else
2565 {
2566 //resref: itemref_12
2567 resref = GetStringLeft(resref, GetStringLength(resref) - 3);
2568 }
2569 int iLvl = StringToInt(sLevel);
2570 if(iLvl == iLevel)
2571 {
2572 object oItem = CreateItemOnObject(resref, oPC, 1);
2573 DelayCommand(1.0*SSE_LOAD_FACTOR, SSE_MessageHandler(oPC, MESSAGE_SUBRACE_ACQUIRED_UNIQUE_ITEM, GetName(oItem)));
2574 SetSubraceDBInt(SUBRACE_DATABASE, SubraceStorage + "_" + SUBRACE_UNIQUEITEM, iLevel, oPC);
2575 SetIdentified(oItem, TRUE);
2576 SetPlotFlag(oItem, TRUE);
2577 SetItemCursedFlag(oItem, TRUE);
2578//b13 added S&D Subrace Objects
2579 if (SEARCH_AND_DESTROY_UNIQUE_OBJECTS)
2580 {
2581 object oCheck = GetFirstItemInInventory(oPC);
2582 string sCheck = GetTag(oItem);
2583 while (oCheck != OBJECT_INVALID)
2584 {
2585 if ((oCheck!=oItem)&&(sCheck == GetTag(oCheck)))
2586 {
2587 DestroyObject(oCheck);
2588 }
2589 oCheck = GetNextItemInInventory(oPC);
2590 }
2591
2592 }
2593//b13 end S&D Objects
2594 }
2595 }
2596 }
2597}
2598
2599void CheckAndGiveSubraceItems(object oPC)
2600{
2601 string SubraceStorage = GetSubraceStorageLocation(GetSubRace(oPC));
2602 GiveSubraceUniqueItem(SubraceStorage, oPC);
2603}
2604int SHA_GetDefaultAppearanceType(object oPC)
2605{
2606 int iRace = GetRacialType(oPC);
2607 int DefaultAppearance;
2608 switch(iRace)
2609 {
2610 case RACIAL_TYPE_DWARF: DefaultAppearance = APPEARANCE_TYPE_DWARF; break;
2611 case RACIAL_TYPE_ELF: DefaultAppearance = APPEARANCE_TYPE_ELF; break;
2612 case RACIAL_TYPE_GNOME: DefaultAppearance = APPEARANCE_TYPE_GNOME; break;
2613 case RACIAL_TYPE_HALFELF: DefaultAppearance = APPEARANCE_TYPE_HALF_ELF; break;
2614 case RACIAL_TYPE_HALFLING: DefaultAppearance = APPEARANCE_TYPE_HALFLING; break;
2615 case RACIAL_TYPE_HALFORC: DefaultAppearance = APPEARANCE_TYPE_HALF_ORC; break;
2616 case RACIAL_TYPE_HUMAN: DefaultAppearance = APPEARANCE_TYPE_HUMAN; break;
2617 default: DefaultAppearance = APPEARANCE_TYPE_HUMAN; break;
2618 }
2619 return DefaultAppearance;
2620}
2621
2622int Subrace_GetFavouredClass(object oPC)
2623{
2624 return GetLocalInt(oPC, SUBRACE_FAVORED_CLASS) - 1;
2625}
2626
2627int GetRacialFavoredClass(int Race)
2628{
2629 int Class = CLASS_TYPE_NONE;
2630 switch(Race)
2631 {
2632 case RACIAL_TYPE_DWARF: Class = CLASS_TYPE_FIGHTER; break;
2633 case RACIAL_TYPE_HUMAN: Class = CLASS_TYPE_ANY; break;
2634 case RACIAL_TYPE_ELF: Class = CLASS_TYPE_WIZARD; break;
2635 case RACIAL_TYPE_GNOME: Class = CLASS_TYPE_WIZARD; break;
2636 case RACIAL_TYPE_HALFELF: Class = CLASS_TYPE_ANY; break;
2637 case RACIAL_TYPE_HALFORC: Class = CLASS_TYPE_BARBARIAN; break;
2638 case RACIAL_TYPE_HALFLING: Class = CLASS_TYPE_ROGUE; break;
2639 }
2640 return Class;
2641}
2642
2643void LoadSubraceFromScript(string Script, int Conditions=SSE_SUBRACE_LOADER_CONDITION_ALWAYS_LOAD)
2644{
2645 int Load=TRUE, Timer=0;
2646 switch(Conditions)
2647 {
2648 case SSE_SUBRACE_LOADER_CONDITION_LOAD_IF_USING_LETO:
2649 Load=ENABLE_LETO;
2650 break;
2651 case SSE_SUBRACE_LOADER_CONDITION_LOAD_IF_NOT_USING_LETO:
2652 Load=(!ENABLE_LETO);
2653 break;
2654 default:
2655 Load=TRUE;
2656 break;
2657 }
2658 if(Load)
2659 {
2660 Timer = GetSSEInt( SSE_SUBRACE_LOADER_AMOUNT);
2661 Timer++;
2662 SetSSEInt( SSE_SUBRACE_LOADER_AMOUNT, Timer);
2663 //A flat 0.0 delay will make the Sub-race script a separate instance.
2664 //But I suppose it never hurt anyone giving the module a little time...
2665 //10ms per script should do for any decent CPU.
2666 DelayCommand((Timer/100.0)*SSE_LOAD_FACTOR, ExecuteScript(Script, oStorer));
2667 }
2668}
2669
2670void SetSSEInt(string VariableName, int Value)
2671{
2672 SetLocalInt(oStorer, VariableName, Value);
2673}
2674
2675int GetSSEInt(string VariableName)
2676{
2677 return GetLocalInt(oStorer, VariableName);
2678}
2679
2680void DeleteSSEInt(string VariableName)
2681{
2682 DeleteLocalInt(oStorer, VariableName);
2683}
2684
2685void SSE_ModuleLoadEvent(int doNWNXInit=FALSE)
2686{
2687 if(doNWNXInit)
2688 {
2689 //Just do this instantly, other external processes may be depent of each.
2690 SetLocalString(oStorer, "NWNX!INIT", "1");
2691 }
2692 int Scripts=GetSSEInt(SSE_SUBRACE_LOADER_AMOUNT);
2693 int Subraces=GetSSEInt( MODULE_SUBRACE_COUNT);
2694 int Delays=GetSSEInt(SSE_SUBRACE_LOADER_AMOUNT_OF_DELAYS);
2695 //If no scripts or no subraces have been found, then this is probably triggered
2696 //before our subrace load scripts.
2697 if(!Scripts && !Subraces && Delays<4)
2698 {
2699 Delays++;
2700 SetSSEInt(SSE_SUBRACE_LOADER_AMOUNT_OF_DELAYS, Delays);
2701 DelayCommand(10.0*SSE_LOAD_FACTOR, SSE_ModuleLoadEvent());
2702 }
2703 //if subraces / scripts have been found, give additional 5 seconds to load the
2704 //remaining files.
2705 else if(!(Delays&0x80000000) )
2706 {
2707 Delays|=0x80000000;
2708 DelayCommand(5.0*SSE_LOAD_FACTOR, SSE_ModuleLoadEvent());
2709 SetSSEInt(SSE_SUBRACE_LOADER_AMOUNT_OF_DELAYS, Delays);
2710 }
2711 //Okay, all subraces should be loaded by now.
2712 else
2713 {
2714 //Calculate time we waited for subraces to load, since this was triggered.
2715 if(Delays&0x80000000)
2716 {
2717 Delays= ((( (Delays&(~0x80000000) ) )<<1) +1 )*5;
2718 }
2719 else
2720 {
2721 Delays*=10;
2722 }
2723 string Output = "*Subrace Engine: Module load completed" +
2724 "\n - Loaded " + IntToString(Subraces) + " subraces." +
2725 "\n - Scripts Executed: " + IntToString(Scripts) +
2726 "\n - Waited " + IntToString(Delays) + " seconds.";
2727 if(SUBRACE_SPELLHOOKS!="")
2728 {
2729 //Use spellhooks
2730 SetModuleOverrideSpellscript(SUBRACE_SPELLHOOKS);
2731 Output +="\n - Spellhook: " + SUBRACE_SPELLHOOKS;
2732 }
2733 Output += "\n NWNX info:";
2734
2735 if(ENABLE_LETO)
2736 {
2737 Output += "\n - Leto Enabled - testing NWNX connection..."+
2738 "\n - Leto is ";
2739 if(LetoPingPong())
2740 {
2741 Output += "replying.";
2742 }
2743 else
2744 {
2745 Output += "NOT working!";
2746 }
2747 }
2748 else
2749 {
2750 Output += "\n - Leto Disabled";
2751 }
2752 Output += "\n - NWNX Database " +(ENABLE_NWNX_DATABASE?"enabled":"disabled")+ ".";
2753 SetSSEInt( SUBRACE_INFO_LOADED_ON_MODULE, TRUE);
2754 Output += "\nEnd of Module Load summery";
2755 WriteTimestampedLogEntry(Output);
2756 Output = "List of loaded sub-races loaded";
2757 int i=1;
2758 for( ; i<= Subraces ; i++)
2759 Output += "\n - " + GetSubraceNameByID(i);
2760 WriteTimestampedLogEntry(Output);
2761 DeleteSSEInt(SSE_SUBRACE_LOADER_AMOUNT);
2762 DeleteSSEInt(SSE_SUBRACE_LOADER_AMOUNT_OF_DELAYS);
2763 }
2764}
2765
2766int GetFavoredClassExceedsGap(int Race1Favored, int Race2Favored, int Class1, int Class2, int Class3, int Class13Gap, int Class23Gap, int Class12Gap)
2767{
2768 //Has PC got Race 1 Favored class?
2769 int iR1Class1Favored = FALSE;
2770 int iR1Class2Favored = FALSE;
2771 int iR1Class3Favored = FALSE;
2772
2773 //Has PC got Race 2 Favored class?
2774 int iR2Class1Favored = FALSE;
2775 int iR2Class2Favored = FALSE;
2776 int iR2Class3Favored = FALSE;
2777
2778 if(Race1Favored == Class1)
2779 {
2780 iR1Class1Favored = TRUE;
2781 }
2782 if(Race1Favored == Class2 && Class2 != CLASS_TYPE_INVALID)
2783 {
2784 iR1Class2Favored = TRUE;
2785 }
2786 if(Race1Favored == Class3 && Class3 != CLASS_TYPE_INVALID)
2787 {
2788 iR1Class3Favored = TRUE;
2789 }
2790
2791 if(Race2Favored == Class1)
2792 {
2793 iR2Class1Favored = TRUE;
2794 }
2795 if(Race2Favored == Class2 && Class2 != CLASS_TYPE_INVALID)
2796 {
2797 iR2Class2Favored = TRUE;
2798 }
2799 if(Race2Favored == Class3 && Class3 != CLASS_TYPE_INVALID)
2800 {
2801 iR2Class3Favored = TRUE;
2802 }
2803
2804 int Exceed12 = FALSE;
2805 int Exceed13 = FALSE;
2806 int Exceed23 = FALSE;
2807
2808 int iResult12 = FALSE;
2809 int iResult13 = FALSE;
2810 int iResult23 = FALSE;
2811
2812 if(abs(Class12Gap) >=2)
2813 {
2814 Exceed12 = TRUE;
2815 }
2816 else if(abs(Class13Gap) >=2)
2817 {
2818 Exceed13 = TRUE;
2819 }
2820 else if(abs(Class23Gap) >=2)
2821 {
2822 Exceed23 = TRUE;
2823 }
2824
2825 if(Exceed12)
2826 {
2827 if(iR1Class1Favored || iR1Class2Favored)
2828 {
2829 iResult12 = TRUE;
2830 if((iR2Class1Favored && Class3 != CLASS_TYPE_INVALID) || (iR2Class2Favored && Class3 != CLASS_TYPE_INVALID))
2831 {
2832 iResult12 = FALSE;
2833 }
2834 }
2835 }
2836 if(Exceed13)
2837 {
2838 if(iR1Class1Favored || iR1Class3Favored)
2839 {
2840 iResult13 = TRUE;
2841 if(iR2Class1Favored ||iR2Class3Favored)
2842 {
2843 iResult13 = FALSE;
2844 }
2845 }
2846 }
2847 if(Exceed23)
2848 {
2849 if(iR1Class2Favored || iR1Class3Favored)
2850 {
2851 iResult23 = TRUE;
2852 if(iR2Class2Favored ||iR2Class3Favored)
2853 {
2854 iResult23 = FALSE;
2855 }
2856 }
2857 }
2858
2859 return (iResult12 || iResult13 || iResult23);
2860}
2861
2862int XPPenaltyOrBoostForSubrace(object oPC, int FClass)
2863{
2864 int iRace = GetRacialType(oPC);
2865 int iRFavored = GetRacialFavoredClass(iRace);
2866
2867 int iSFavored = FClass;
2868 if(iSFavored == iRFavored)
2869 {
2870 return SUBRACE_XP_UNCHANGED;
2871 }
2872
2873 int Class1 = GetClassByPosition(1, oPC);
2874 int Class2 = GetClassByPosition(2, oPC);
2875 int Class3 = GetClassByPosition(3, oPC);
2876
2877 int Class1Level = GetLevelByClass(Class1, oPC);
2878 int Class2Level = GetLevelByClass(Class2, oPC);
2879 int Class3Level = GetLevelByClass(Class3, oPC);
2880
2881 if(iRFavored == CLASS_TYPE_ANY)
2882 {
2883 int Max1 = Max(Class1Level, Class2Level);
2884 int Max2 = Max(Max1, Class3Level);
2885
2886 if(Max2 == Class1Level)
2887 {
2888 iRFavored = Class1;
2889 }
2890 else if(Max2 == Class2Level)
2891 {
2892 iRFavored = Class2;
2893 }
2894 else if(Max2 == Class3Level)
2895 {
2896 iRFavored = Class3;
2897 }
2898 }
2899
2900 if(iSFavored == CLASS_TYPE_ANY)
2901 {
2902 int Max1 = Max(Class1Level, Class2Level);
2903 int Max2 = Max(Max1, Class3Level);
2904
2905 if(Max2 == Class1Level)
2906 {
2907 iSFavored = Class1;
2908 }
2909 else if(Max2 == Class2Level)
2910 {
2911 iSFavored = Class2;
2912 }
2913 else if(Max2 == Class3Level)
2914 {
2915 iSFavored = Class3;
2916 }
2917 }
2918
2919 int Class12Gap = Class1Level - Class2Level;
2920 int Class13Gap = Class1Level - Class3Level;
2921 int Class23Gap = Class2Level - Class3Level;
2922
2923 if(Class2Level == 0)
2924 {
2925 Class12Gap = 0;
2926 Class23Gap = 0;
2927 }
2928 if(Class3Level == 0)
2929 {
2930 Class13Gap = 0;
2931 }
2932 int SubraceFClassExcGap = FALSE;
2933 int RacialFClassExcGap = FALSE;
2934
2935 if(SUBRACE_IGNORE_BASE_RACE_FAVORED_CLASS)
2936 {
2937 RacialFClassExcGap = GetFavoredClassExceedsGap(iRFavored, iSFavored, Class1, Class2, Class3, Class13Gap, Class23Gap, Class12Gap);
2938 }
2939
2940 SubraceFClassExcGap = GetFavoredClassExceedsGap(iSFavored, iRFavored, Class1, Class2, Class3, Class13Gap, Class23Gap, Class12Gap);
2941 //Racial Favored Class Exceeds the Multiclass Level gap, and Subrace Favored class does not
2942 //So give a decrease in XP to counter NWN engine XP distribution.
2943 if(RacialFClassExcGap && !SubraceFClassExcGap)
2944 {
2945 return SUBRACE_XP_DECREASE;
2946 }
2947 //Subrace Favored Class Exceeds the Multiclass Level gap, and Racial Favored class does not
2948 //So give a boost in XP to override the NWN engine XP distribution.
2949 else if(!RacialFClassExcGap && SubraceFClassExcGap)
2950 {
2951 return SUBRACE_XP_BOOST;
2952 }
2953 //Both exceed the Multiclass Level gap or do not.
2954 //So since the effects of both exceeding cancel each other out, return normal XP.
2955 return SUBRACE_XP_UNCHANGED;
2956}
2957
2958float GetSubraceXPModifier(object oPC)
2959{
2960 int FClass = Subrace_GetFavouredClass(oPC);
2961 float iMod = 1.0;
2962 if(FClass != -1)
2963 {
2964 int XPMod = XPPenaltyOrBoostForSubrace(oPC, FClass);
2965
2966 if(XPMod == SUBRACE_XP_BOOST)
2967 {
2968 iMod = 1.25;
2969 }
2970 else if(XPMod == SUBRACE_XP_DECREASE)
2971 {
2972 iMod = 0.8;
2973 }
2974 }
2975 return iMod;
2976
2977}
2978
2979int GetECL(object oPC)
2980{
2981 string SubraceStorage = GetSubraceStorageLocationByID(GetPlayerSubraceID(oPC));
2982 return GetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_ECL);
2983}
2984
2985int Subrace_GetIsUndead(object oPC)
2986{
2987 if(!GetIsPC(oPC)) { return FALSE; }
2988 int ID = GetPlayerSubraceID(oPC);
2989 if(!ID) { return FALSE; }
2990 string SubraceStorage = GetSubraceStorageLocationByID(ID);
2991 return GetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_UNDEAD, SUBRACE_BASE_INFORMATION_FLAGS);
2992
2993}
2994void ApplyUniqueSubraceEffect(object oPC, string SubraceStorage, int iEffect)
2995{
2996 if(iEffect == 0)
2997 { return; }
2998 int Value1 = GetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_EFFECT,SUBRACE_EFFECT_VALUE1_FLAGSET);
2999 int Value2 = GetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_EFFECT,SUBRACE_EFFECT_VALUE2_FLAGSET);
3000 int DurationType = GetSSEInt( SubraceStorage + "_" + SUBRACE_EFFECT_DURATION_TYPE);
3001 float fDuration = GetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_EFFECT_DURATION);
3002 effect eEffect = SHA_GetEffectFromID(iEffect, Value1, Value2);
3003 effect eEffectApp = SupernaturalEffect(eEffect);
3004 AssignCommand(oStorer, ApplyEffectToObject(DurationType, eEffectApp, oPC, fDuration));
3005}
3006void ApplySubraceEffect(object oPC, string SubraceStorage, int TimeOfDay)
3007{
3008 int EffectCount = GetSSEInt( SubraceStorage + "_" + SUBRACE_EFFECT_COUNT);
3009 if(EffectCount == 0)
3010 {
3011 return;
3012 }
3013 ClearSubraceEffects(oPC);
3014 int i = 0;
3015 while(i != EffectCount)
3016 {
3017 i++;
3018 string SubraceStorage1 = SubraceStorage + IntToString(i);
3019 int EffectID = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + SUBRACE_EFFECT,SUBRACE_EFFECT_FLAGSET);
3020 int EffectTimeOfDay = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + SUBRACE_EFFECT,SUBRACE_EFFECT_TIME_FLAGSET);
3021 if(EffectTimeOfDay == TIME_BOTH || EffectTimeOfDay == TimeOfDay)
3022 {
3023 ApplyUniqueSubraceEffect(oPC, SubraceStorage1, EffectID);
3024 }
3025 }
3026 SSE_MessageHandler(oPC, MESSAGE_SUBRACE_EFFECTS_APPLIED);
3027}
3028
3029void ApplySubrace(object oTarget, string subrace)
3030{
3031 subrace = GetStringLowerCase(subrace);
3032 if(ENABLE_LETO)
3033 {
3034 SetLocalString(oTarget, "SUBR_PlayerName", GetPCPlayerName(oTarget));
3035 DelayCommand(4.0*SSE_LOAD_FACTOR, SetLocalString(oTarget, "SUBR_FileName", GetBicFileName(oTarget)));
3036 }
3037 DeleteSubraceInfoOnPC(oTarget);
3038 int ID = GetSubraceID(subrace);
3039 DelayCommand(1.5*SSE_LOAD_FACTOR, LoadSubraceInfoOnPC(oTarget, subrace));
3040 DelayCommand(2.6*SSE_LOAD_FACTOR, SetSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + "_" + GetSubraceNameByAlias(subrace, TRUE), SUBRACE_ACCEPTED, oTarget));
3041 DelayCommand(4.0*SSE_LOAD_FACTOR, ApplyPermanentSubraceSpellResistance(ID, oTarget));
3042 DelayCommand(5.5*SSE_LOAD_FACTOR, ApplyPermanentSubraceAppearance(ID, oTarget));
3043// 3.0.6.6
3044 DelayCommand(6.0*SSE_LOAD_FACTOR, ApplySubraceColors(oTarget));
3045 DelayCommand(6.5*SSE_LOAD_FACTOR, ApplySubraceEyeColors(oTarget));
3046
3047//3.0.6.9
3048 DelayCommand(7.0*SSE_LOAD_FACTOR, ApplySubraceHead(oTarget));
3049
3050 DelayCommand(7.5*SSE_LOAD_FACTOR, CheckIfCanUseEquipedWeapon(oTarget));
3051 DelayCommand(11.5*SSE_LOAD_FACTOR,CheckIfCanUseEquippedArmor(oTarget));
3052}
3053
3054//3.0.6.6
3055
3056void ApplySubraceColors(object oPC)
3057{
3058 string SubraceStorage = GetSubraceStorageLocation(GetStringLowerCase(GetSubRace(oPC)));
3059
3060 int Level = GetPlayerLevel(oPC);
3061 while (Level)
3062 {
3063 string SubraceStorage1 = SubraceStorage + "_" + IntToString(Level);
3064 int Gender = GetGender(oPC);
3065 if(GetSSEInt( SubraceStorage1 + "_" + SUBRACE_COLORS_FLAGS) )
3066 {
3067 int Hair = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + SUBRACE_COLORS_FLAGS, (Gender==GENDER_MALE?SUBRACE_COLORS_FLAGS_HAIR_MALE:SUBRACE_COLORS_FLAGS_HAIR_FEMALE) );
3068 int Skin = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + SUBRACE_COLORS_FLAGS, (Gender==GENDER_MALE?SUBRACE_COLORS_FLAGS_SKIN_MALE:SUBRACE_COLORS_FLAGS_SKIN_FEMALE) );
3069 if ((Hair>-1)||(Skin>-1))
3070 {
3071 if (Hair>-1)
3072 {
3073 SetColor(oPC, COLOR_CHANNEL_HAIR, Hair);
3074 }
3075 if (Skin>-1)
3076 {
3077 SetColor(oPC, COLOR_CHANNEL_SKIN, Skin);
3078 }
3079 return;
3080 }
3081 }
3082 Level--;
3083 }
3084}
3085
3086//3.0.6.6
3087void SHA_SetEyeColor(object oPC, int iEyes = -1)
3088{
3089 effect eEffect, eVisEyes;
3090 int iGender = GetGender(oPC), iSub, iType;
3091 switch (iEyes)
3092 {
3093 case SSE_EYE_COLOR_CYAN:
3094 {
3095 switch(GetRacialType(oPC))
3096 {
3097 case RACIAL_TYPE_DWARF:
3098 {
3099 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_CYN_DWARF_MALE);
3100 else eVisEyes = EffectVisualEffect(VFX_EYES_CYN_DWARF_FEMALE);
3101 break;
3102 }
3103 case RACIAL_TYPE_ELF:
3104 {
3105 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_CYN_ELF_MALE);
3106 else eVisEyes = EffectVisualEffect(VFX_EYES_CYN_ELF_FEMALE);
3107 break;
3108 }
3109 case RACIAL_TYPE_GNOME:
3110 {
3111 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_CYN_GNOME_MALE);
3112 else eVisEyes = EffectVisualEffect(VFX_EYES_CYN_GNOME_FEMALE);
3113 break;
3114 }
3115 case RACIAL_TYPE_HALFELF:
3116 {
3117 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_CYN_HUMAN_MALE);
3118 else eVisEyes = EffectVisualEffect(VFX_EYES_CYN_HUMAN_FEMALE);
3119 break;
3120 }
3121 case RACIAL_TYPE_HALFLING:
3122 {
3123 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_CYN_HALFLING_MALE);
3124 else eVisEyes = EffectVisualEffect(VFX_EYES_CYN_HALFLING_FEMALE);
3125 break;
3126 }
3127 case RACIAL_TYPE_HALFORC:
3128 {
3129 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_CYN_HALFORC_MALE);
3130 else eVisEyes = EffectVisualEffect(VFX_EYES_CYN_HALFORC_FEMALE);
3131 break;
3132 }
3133 case RACIAL_TYPE_HUMAN:
3134 {
3135 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_CYN_HUMAN_MALE);
3136 else eVisEyes = EffectVisualEffect(VFX_EYES_CYN_HUMAN_FEMALE);
3137 break;
3138 }
3139 }
3140 break;
3141 }
3142 case SSE_EYE_COLOR_GREEN:
3143 {
3144 switch(GetRacialType(oPC))
3145 {
3146 case RACIAL_TYPE_DWARF:
3147 {
3148 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_DWARF_MALE);
3149 else eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_DWARF_FEMALE);
3150 break;
3151 }
3152 case RACIAL_TYPE_ELF:
3153 {
3154 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_ELF_MALE);
3155 else eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_ELF_FEMALE);
3156 break;
3157 }
3158 case RACIAL_TYPE_GNOME:
3159 {
3160 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_GNOME_MALE);
3161 else eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_GNOME_FEMALE);
3162 break;
3163 }
3164 case RACIAL_TYPE_HALFELF:
3165 {
3166 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_HUMAN_MALE);
3167 else eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_HUMAN_FEMALE);
3168 break;
3169 }
3170 case RACIAL_TYPE_HALFLING:
3171 {
3172 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_HALFLING_MALE);
3173 else eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_HALFLING_FEMALE);
3174 break;
3175 }
3176 case RACIAL_TYPE_HALFORC:
3177 {
3178 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_HALFORC_MALE);
3179 else eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_HALFORC_FEMALE);
3180 break;
3181 }
3182 case RACIAL_TYPE_HUMAN:
3183 {
3184 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_HUMAN_MALE);
3185 else eVisEyes = EffectVisualEffect(VFX_EYES_GREEN_HUMAN_FEMALE);
3186 break;
3187 }
3188 }
3189 break;
3190 }
3191 case SSE_EYE_COLOR_ORANGE:
3192 {
3193 switch(GetRacialType(oPC))
3194 {
3195 case RACIAL_TYPE_DWARF:
3196 {
3197 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_ORG_DWARF_MALE);
3198 else eVisEyes = EffectVisualEffect(VFX_EYES_ORG_DWARF_FEMALE);
3199 break;
3200 }
3201 case RACIAL_TYPE_ELF:
3202 {
3203 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_ORG_ELF_MALE);
3204 else eVisEyes = EffectVisualEffect(VFX_EYES_ORG_ELF_FEMALE);
3205 break;
3206 }
3207 case RACIAL_TYPE_GNOME:
3208 {
3209 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_ORG_GNOME_MALE);
3210 else eVisEyes = EffectVisualEffect(VFX_EYES_ORG_GNOME_FEMALE);
3211 break;
3212 }
3213 case RACIAL_TYPE_HALFELF:
3214 {
3215 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_ORG_HUMAN_MALE);
3216 else eVisEyes = EffectVisualEffect(VFX_EYES_ORG_HUMAN_FEMALE);
3217 break;
3218 }
3219 case RACIAL_TYPE_HALFLING:
3220 {
3221 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_ORG_HALFLING_MALE);
3222 else eVisEyes = EffectVisualEffect(VFX_EYES_ORG_HALFLING_FEMALE);
3223 break;
3224 }
3225 case RACIAL_TYPE_HALFORC:
3226 {
3227 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_ORG_HALFORC_MALE);
3228 else eVisEyes = EffectVisualEffect(VFX_EYES_ORG_HALFORC_FEMALE);
3229 break;
3230 }
3231 case RACIAL_TYPE_HUMAN:
3232 {
3233 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_ORG_HUMAN_MALE);
3234 else eVisEyes = EffectVisualEffect(VFX_EYES_ORG_HUMAN_FEMALE);
3235 break;
3236 }
3237 }
3238 break;
3239 }
3240 case SSE_EYE_COLOR_PURPLE:
3241 {
3242 switch(GetRacialType(oPC))
3243 {
3244 case RACIAL_TYPE_DWARF:
3245 {
3246 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_PUR_DWARF_MALE);
3247 else eVisEyes = EffectVisualEffect(VFX_EYES_PUR_DWARF_FEMALE);
3248 break;
3249 }
3250 case RACIAL_TYPE_ELF:
3251 {
3252 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_PUR_ELF_MALE);
3253 else eVisEyes = EffectVisualEffect(VFX_EYES_PUR_ELF_FEMALE);
3254 break;
3255 }
3256 case RACIAL_TYPE_GNOME:
3257 {
3258 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_PUR_GNOME_MALE);
3259 else eVisEyes = EffectVisualEffect(VFX_EYES_PUR_GNOME_FEMALE);
3260 break;
3261 }
3262 case RACIAL_TYPE_HALFELF:
3263 {
3264 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_PUR_HUMAN_MALE);
3265 else eVisEyes = EffectVisualEffect(VFX_EYES_PUR_HUMAN_FEMALE);
3266 break;
3267 }
3268 case RACIAL_TYPE_HALFLING:
3269 {
3270 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_PUR_HALFLING_MALE);
3271 else eVisEyes = EffectVisualEffect(VFX_EYES_PUR_HALFLING_FEMALE);
3272 break;
3273 }
3274 case RACIAL_TYPE_HALFORC:
3275 {
3276 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_PUR_HALFORC_MALE);
3277 else eVisEyes = EffectVisualEffect(VFX_EYES_PUR_HALFORC_FEMALE);
3278 break;
3279 }
3280 case RACIAL_TYPE_HUMAN:
3281 {
3282 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_PUR_HUMAN_MALE);
3283 else eVisEyes = EffectVisualEffect(VFX_EYES_PUR_HUMAN_FEMALE);
3284 break;
3285 }
3286 }
3287 break;
3288 }
3289 case SSE_EYE_COLOR_RED:
3290 {
3291 switch(GetRacialType(oPC))
3292 {
3293 case RACIAL_TYPE_DWARF:
3294 {
3295 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_DWARF_MALE);
3296 else eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_DWARF_FEMALE);
3297 break;
3298 }
3299 case RACIAL_TYPE_ELF:
3300 {
3301 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_ELF_MALE);
3302 else eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_ELF_FEMALE);
3303 break;
3304 }
3305 case RACIAL_TYPE_GNOME:
3306 {
3307 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_GNOME_MALE);
3308 else eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_GNOME_FEMALE);
3309 break;
3310 }
3311 case RACIAL_TYPE_HALFELF:
3312 {
3313 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_HALFELF_MALE);
3314 else eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_HALFELF_FEMALE);
3315 break;
3316 }
3317 case RACIAL_TYPE_HALFLING:
3318 {
3319 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_HALFLING_MALE);
3320 else eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_HALFLING_FEMALE);
3321 break;
3322 }
3323 case RACIAL_TYPE_HALFORC:
3324 {
3325 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_HALFORC_MALE);
3326 else eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_HALFORC_FEMALE);
3327 break;
3328 }
3329 case RACIAL_TYPE_HUMAN:
3330 {
3331 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_HUMAN_MALE);
3332 else eVisEyes = EffectVisualEffect(VFX_EYES_RED_FLAME_HUMAN_FEMALE);
3333 break;
3334 }
3335 }
3336 break;
3337 }
3338 case SSE_EYE_COLOR_WHITE:
3339 {
3340 switch(GetRacialType(oPC))
3341 {
3342 case RACIAL_TYPE_DWARF:
3343 {
3344 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_WHT_DWARF_MALE);
3345 else eVisEyes = EffectVisualEffect(VFX_EYES_WHT_DWARF_FEMALE);
3346 break;
3347 }
3348 case RACIAL_TYPE_ELF:
3349 {
3350 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_WHT_ELF_MALE);
3351 else eVisEyes = EffectVisualEffect(VFX_EYES_WHT_ELF_FEMALE);
3352 break;
3353 }
3354 case RACIAL_TYPE_GNOME:
3355 {
3356 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_WHT_GNOME_MALE);
3357 else eVisEyes = EffectVisualEffect(VFX_EYES_WHT_GNOME_FEMALE);
3358 break;
3359 }
3360 case RACIAL_TYPE_HALFELF:
3361 {
3362 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_WHT_HUMAN_MALE);
3363 else eVisEyes = EffectVisualEffect(VFX_EYES_WHT_HUMAN_FEMALE);
3364 break;
3365 }
3366 case RACIAL_TYPE_HALFLING:
3367 {
3368 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_WHT_HALFLING_MALE);
3369 else eVisEyes = EffectVisualEffect(VFX_EYES_WHT_HALFLING_FEMALE);
3370 break;
3371 }
3372 case RACIAL_TYPE_HALFORC:
3373 {
3374 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_WHT_HALFORC_MALE);
3375 else eVisEyes = EffectVisualEffect(VFX_EYES_WHT_HALFORC_FEMALE);
3376 break;
3377 }
3378 case RACIAL_TYPE_HUMAN:
3379 {
3380 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_WHT_HUMAN_MALE);
3381 else eVisEyes = EffectVisualEffect(VFX_EYES_WHT_HUMAN_FEMALE);
3382 break;
3383 }
3384 }
3385 break;
3386 }
3387 case SSE_EYE_COLOR_YELLOW:
3388 {
3389 switch(GetRacialType(oPC))
3390 {
3391 case RACIAL_TYPE_DWARF:
3392 {
3393 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_YEL_DWARF_MALE);
3394 else eVisEyes = EffectVisualEffect(VFX_EYES_YEL_DWARF_FEMALE);
3395 break;
3396 }
3397 case RACIAL_TYPE_ELF:
3398 {
3399 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_YEL_ELF_MALE);
3400 else eVisEyes = EffectVisualEffect(VFX_EYES_YEL_ELF_FEMALE);
3401 break;
3402 }
3403 case RACIAL_TYPE_GNOME:
3404 {
3405 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_YEL_GNOME_MALE);
3406 else eVisEyes = EffectVisualEffect(VFX_EYES_YEL_GNOME_FEMALE);
3407 break;
3408 }
3409 case RACIAL_TYPE_HALFELF:
3410 {
3411 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_YEL_HUMAN_MALE);
3412 else eVisEyes = EffectVisualEffect(VFX_EYES_YEL_HUMAN_FEMALE);
3413 break;
3414 }
3415 case RACIAL_TYPE_HALFLING:
3416 {
3417 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_YEL_HALFLING_MALE);
3418 else eVisEyes = EffectVisualEffect(VFX_EYES_YEL_HALFLING_FEMALE);
3419 break;
3420 }
3421 case RACIAL_TYPE_HALFORC:
3422 {
3423 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_YEL_HALFORC_MALE);
3424 else eVisEyes = EffectVisualEffect(VFX_EYES_YEL_HALFORC_FEMALE);
3425 break;
3426 }
3427 case RACIAL_TYPE_HUMAN:
3428 {
3429 if (iGender == GENDER_MALE) eVisEyes = EffectVisualEffect(VFX_EYES_YEL_HUMAN_MALE);
3430 else eVisEyes = EffectVisualEffect(VFX_EYES_YEL_HUMAN_FEMALE);
3431 break;
3432 }
3433 }
3434 break;
3435 }
3436 }
3437 eEffect = GetFirstEffect(oPC);
3438 while (GetIsEffectValid(eEffect))
3439 {
3440 iType = GetEffectType(eEffect);
3441 iSub = GetEffectSubType(eEffect);
3442 if (iType == EFFECT_TYPE_VISUALEFFECT && iSub == SUBTYPE_SUPERNATURAL)
3443 {
3444 RemoveEffect(oPC, eEffect);
3445 }
3446 eEffect = GetNextEffect(oPC);
3447 }
3448 ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(eVisEyes), oPC);
3449}
3450
3451//3.0.6.9
3452void ApplySubraceHead(object oPC)
3453{
3454 string SubraceStorage = GetSubraceStorageLocation(GetStringLowerCase(GetSubRace(oPC)));
3455 int Level = GetPlayerLevel(oPC);
3456 while (Level)
3457 {
3458 string SubraceStorage1 = SubraceStorage + "_" + IntToString(Level);
3459 int Gender = GetGender(oPC);
3460 if(GetSSEInt( SubraceStorage1 + "_" + SUBRACE_HEAD_FLAGS) )
3461 {
3462 int iHead = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + SUBRACE_HEAD_FLAGS, (Gender==GENDER_MALE?SUBRACE_HEAD_FLAGS_MALE:SUBRACE_HEAD_FLAGS_FEMALE) );
3463 if (iHead>-1)
3464 {
3465 SetCreatureBodyPart(CREATURE_PART_HEAD,iHead,oPC);
3466 return;
3467 }
3468 }
3469 Level--;
3470 }
3471}
3472
3473//3.0.6.6
3474void ApplySubraceEyeColors(object oPC)
3475{
3476 string SubraceStorage = GetSubraceStorageLocation(GetStringLowerCase(GetSubRace(oPC)));
3477 int Level = GetPlayerLevel(oPC);
3478 while (Level)
3479 {
3480 string SubraceStorage1 = SubraceStorage + "_" + IntToString(Level);
3481 int Gender = GetGender(oPC);
3482 if(GetSSEInt( SubraceStorage1 + "_" + SUBRACE_EYE_COLORS_FLAGS) )
3483 {
3484 int iEyes = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + SUBRACE_EYE_COLORS_FLAGS, (Gender==GENDER_MALE?SUBRACE_EYE_COLORS_FLAGS_MALE:SUBRACE_EYE_COLORS_FLAGS_FEMALE) );
3485 if (iEyes>-1)
3486 {
3487 SHA_SetEyeColor(oPC, iEyes);
3488 return;
3489 }
3490 }
3491 Level--;
3492 }
3493}
3494
3495//3.0.6.9 - Rewrite by moon
3496void LoadSubraceInfoOnPC(object oPC, string subrace)
3497{
3498 if(GetLocalInt(oPC, SUBRACE_INFO_LOADED_ON_PC))
3499 {
3500 ReapplySubraceAbilities(oPC);
3501 return;
3502 }
3503
3504
3505 if(subrace == "")
3506 {
3507 return;
3508 }
3509
3510 // subrace = GetStringLowerCase(subrace); //DATABASE req. lowercase for compatibility with < 3.0.5
3511//3.0.6.9 extra optimazation
3512 int ID = GetSubraceID(subrace);
3513 string subraceBaseName = GetSubraceNameByID(ID);
3514 string subraceBaseNameLower = GetStringLowerCase(subraceBaseName);
3515 //Oh oh, someone has removed the subrace! >.<
3516 if(!ID)
3517 {
3518 SSE_MessageHandler(oPC, MESSAGE_SUBRACE_IS_MISSING_FROM_SERVER);
3519 return;
3520 }
3521
3522 if(!(SSE_TREAT_ALIAS_AS_SUBRACE & 1))
3523 {
3524 SSE_MessageHandler(oPC, MESSAGE_SUBRACE_ALIAS_UNIFORMIZING,subrace, subraceBaseName );
3525 SetSubRace(oPC, subraceBaseName);
3526 subrace = subraceBaseName;
3527 }
3528 else if (subrace != subraceBaseName)
3529 {
3530 SSE_MessageHandler(oPC, MESSAGE_SUBRACE_ALIAS_DIVERSITY, subraceBaseName );
3531 }
3532
3533 SetSubRace(oPC, subrace);
3534 string SubraceStorage = GetSubraceStorageLocation(subrace);
3535
3536 SSE_MessageHandler(oPC, MESSAGE_SUBRACE_LOADING_DATA, subrace );
3537
3538 int Gender = GetGender(oPC);
3539
3540 GiveSubraceUniqueItem(SubraceStorage, oPC);
3541 int iTime = SHA_GetCurrentTime();
3542 DelayCommand(3.0*SSE_LOAD_FACTOR, SetLocalInt(oPC, SUBRACE_INFO_LOADED_ON_PC, TRUE));
3543 DelayCommand(4.0*SSE_LOAD_FACTOR, ApplyTemporarySubraceAppearance(SubraceStorage, oPC, iTime));
3544 DelayCommand(4.5*SSE_LOAD_FACTOR, ChangeMiscellaneousSubraceStuff(oPC, GetPlayerLevel(oPC)));
3545 DelayCommand(5.5*SSE_LOAD_FACTOR, ApplySubraceEffect(oPC, SubraceStorage, iTime));
3546 DelayCommand(6.5*SSE_LOAD_FACTOR, ApplyPermanentSubraceSpellResistance(ID, oPC));
3547 DelayCommand(7.5*SSE_LOAD_FACTOR, ApplyPermanentSubraceAppearance(ID, oPC));
3548
3549//3.0.6.6
3550 DelayCommand(8.0*SSE_LOAD_FACTOR, ApplySubraceColors(oPC));
3551 DelayCommand(8.5*SSE_LOAD_FACTOR, ApplySubraceEyeColors(oPC));
3552
3553//3.0.6.9
3554 DelayCommand(9.0*SSE_LOAD_FACTOR, ApplySubraceHead(oPC));
3555
3556 DelayCommand(10.0*SSE_LOAD_FACTOR, EquipTemporarySubraceSkin(SubraceStorage, oPC, iTime));
3557 DelayCommand(13.0*SSE_LOAD_FACTOR, EquipTemporarySubraceClaw(SubraceStorage, oPC, iTime));
3558 DelayCommand(14.0*SSE_LOAD_FACTOR, SSE_MessageHandler(oPC, MESSAGE_SUBRACE_DATA_LOADED));
3559 DelayCommand(20.0*SSE_LOAD_FACTOR, ChangeSubraceFactions(oPC, subrace));
3560
3561 int Level = GetPlayerLevel(oPC);
3562 int NeedsToRelog = CheckForLetoReLog(oPC, Level);
3563 if(NeedsToRelog)
3564 {
3565 if(!LETO_ACTIVATE_PORTAL)
3566 {
3567 DelayCommand(24.0*SSE_LOAD_FACTOR, PopUpDeathGUIPanel(oPC, FALSE, FALSE, 0, SUBRACE_ENGINE + SSE_GetStandardMessage(MESSAGE_LETO_PLEASE_RELOG)));
3568 if(LETO_AUTOMATICALLY_BOOT)
3569 {
3570 DelayCommand(24.2*SSE_LOAD_FACTOR, SSE_MessageHandler(oPC, MESSAGE_LETO_AUTOBOOT, IntToString(LETO_AUTOMATIC_BOOT_DELAY) ));
3571 DelayCommand((24.2*SSE_LOAD_FACTOR) + IntToFloat(LETO_AUTOMATIC_BOOT_DELAY), DelayBoot(oPC));
3572 }
3573 }
3574 else
3575 {
3576 if(!LETO_PORTAL_KEEP_CHARACTER_IN_THE_SAME_PLACE)
3577 {
3578 DelayCommand(24.2*SSE_LOAD_FACTOR, SSE_MessageHandler(oPC, MESSAGE_LETO_AUTOPORTAL, IntToString(LETO_AUTOMATIC_PORTAL_DELAY) ));
3579//b13 fix
3580 DelayCommand(24.2*SSE_LOAD_FACTOR +
3581 IntToFloat(LETO_AUTOMATIC_PORTAL_DELAY),
3582 ActivatePortal(oPC, LETO_PORTAL_IP_ADDRESS,
3583 LETO_PORTAL_SERVER_PASSWORD,
3584 LETO_PORTAL_WAYPOINT, TRUE));
3585 }
3586 else
3587 {
3588 int RandomNumber = d100(1);
3589 string sWPTag = "WP_SUBRACE_P" + IntToString(RandomNumber);
3590 object oWaypoint = CreateObject(OBJECT_TYPE_WAYPOINT, "nw_waypoint001", GetLocation(oPC), FALSE, sWPTag);
3591 DelayCommand(24.2*SSE_LOAD_FACTOR, SSE_MessageHandler(oPC, MESSAGE_LETO_DONT_PANIC_JUSTPORTING));
3592//b13 fix
3593 DelayCommand(24.2*SSE_LOAD_FACTOR + IntToFloat(LETO_AUTOMATIC_PORTAL_DELAY), ActivatePortal(oPC, LETO_PORTAL_IP_ADDRESS, LETO_PORTAL_SERVER_PASSWORD, sWPTag, TRUE));
3594 DelayCommand(24.2*SSE_LOAD_FACTOR + IntToFloat(LETO_AUTOMATIC_PORTAL_DELAY), DestroyObject(oWaypoint, 0.1));
3595 }
3596 }
3597 DelayCommand(18.0*SSE_LOAD_FACTOR, SetSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + LETO_CHANGES_MADE_FOR_THIS_LEVEL + "_" + subraceBaseNameLower, Level, oPC));
3598 }
3599}
3600
3601void DeleteSubraceInfoInDatabase(object oPC, string subrace)
3602{
3603 DeleteSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + LETO_CHANGES_MADE_FOR_THIS_LEVEL + "_" + subrace, oPC);
3604 DeleteSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + subrace, oPC);
3605}
3606
3607void DeleteSubraceInfoOnPC(object oPC, int ClearSubraceField=FALSE)
3608{
3609 string subrace = GetSubRace(oPC);
3610 string SubraceStorage = GetSubraceStorageLocation(subrace);
3611
3612 if(subrace == "")
3613 { return; }
3614
3615 DelayCommand(0.2*SSE_LOAD_FACTOR, DeleteSubraceInfoInDatabase(oPC, GetSubraceNameByAlias(subrace, TRUE)));
3616
3617 SSE_MessageHandler(oPC, MESSAGE_SUBRACE_PURGING);
3618 ClearSubraceTemporaryStats(oPC);
3619 ClearSubraceEffects(oPC);
3620 ChangeToPCDefaultAppearance(oPC);
3621 effect iEffect = GetFirstEffect(oPC);
3622 while(GetIsEffectValid(iEffect))
3623 {
3624 int iEffectType = GetEffectType(iEffect);
3625 if(iEffectType == EFFECT_TYPE_SPELL_RESISTANCE_INCREASE ||
3626 iEffectType == EFFECT_TYPE_SPELL_RESISTANCE_DECREASE)
3627 {
3628 RemoveEffect(oPC, iEffect);
3629 }
3630 iEffect = GetNextEffect(oPC);
3631 }
3632
3633 DeleteLocalInt(oPC, SUBRACE_INFO_LOADED_ON_PC);
3634
3635 object Skin = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oPC);
3636 SetPlotFlag(Skin, FALSE);
3637 DestroyObject(Skin, 0.1*SSE_LOAD_FACTOR);
3638
3639 //::****************************************************************
3640 // 1.69 -- Add horse menu and new skin if needed
3641 if( (GetIsPC( oPC) || GetIsDM( oPC)) &&
3642 (GetSkinHasHorseMenu( Skin) || (!GetIsObjectValid( Skin) && !GetHasFeat( FEAT_HORSE_MENU, oPC))))
3643 { SSE_HorseAddHorseMenu( oPC);
3644 }
3645 //::****************************************************************
3646
3647 object ClawLeft = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oPC);
3648 object ClawRight = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oPC);
3649 SetPlotFlag(ClawLeft, FALSE);
3650 SetPlotFlag(ClawRight, FALSE);
3651 DestroyObject(ClawLeft, 0.5*SSE_LOAD_FACTOR);
3652 DestroyObject(ClawRight, 0.5*SSE_LOAD_FACTOR);
3653
3654 int SubraceUniqueItemCount = GetSSEInt( SubraceStorage + "_" + SUBRACE_UNIQUEITEM_COUNT);
3655 int i = 0;
3656 while(i <= SubraceUniqueItemCount)
3657 {
3658 i++;
3659 string resref = GetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_UNIQUEITEM + "_" + IntToString(i));
3660 if(resref != "")
3661 {
3662 string sLevel = GetStringRight(resref, 2);
3663 if(GetStringLeft(sLevel, 1) == "_")
3664 {
3665 sLevel = GetStringRight(sLevel, 1);
3666 }
3667 int iLevel = StringToInt(sLevel);
3668 resref = GetStringLeft(resref, GetStringLength(resref) - 2);
3669 if(iLevel <= GetPlayerLevel(oPC))
3670 {
3671 object oItem = GetFirstItemInInventory(oPC);
3672 while(GetIsObjectValid(oItem))
3673 {
3674 if(GetResRef(oItem) == resref)
3675 {
3676 SetPlotFlag(oItem, FALSE);
3677 DestroyObject(oItem, 0.1*SSE_LOAD_FACTOR);
3678 }
3679 oItem = GetNextItemInInventory(oPC);
3680 }
3681 }
3682 }
3683 }
3684 SetCreatureWingType(CREATURE_WING_TYPE_NONE, oPC);
3685 SetCreatureTailType(CREATURE_TAIL_TYPE_NONE, oPC);
3686 DeleteLocalInt(oPC, SUBRACE_TAG + "SB_NITE_OCE");
3687 DeleteLocalInt(oPC, SUBRACE_TAG + "SB_DAY_OCE");
3688
3689 DeleteLocalInt(oPC, SUBRACE_IN_SPELL_DARKNESS);
3690 DeleteLocalInt(oPC, "SUB_EFCT_D_APD");
3691 DeleteLocalInt(oPC, "SUB_EFCT_N_APD");
3692
3693 DeleteLocalInt(oPC,"SB_LGHT_DMGED");
3694
3695 DeleteLocalInt(oPC,"SB_DARK_DMGED");
3696
3697 DeleteLocalInt(oPC, SUBRACE_STATS_STATUS);
3698 if(ClearSubraceField)
3699 {
3700 if(subrace == "")
3701 {
3702 //3.0.6.5
3703 DelayCommand(0.5*SSE_LOAD_FACTOR, SetSubRace(oPC, ""));
3704 if (USE_SSE_DEFAULT_RACES)
3705 {
3706 DelayCommand(0.6*SSE_LOAD_FACTOR, CheckAndApplyDefaultSubrace(oPC));
3707 }
3708 }
3709 }
3710 DelayCommand(1.0*SSE_LOAD_FACTOR, SSE_MessageHandler(oPC, MESSAGE_SUBRACE_PURGED));
3711
3712}
3713
3714
3715string Subrace_TimeToString(int iTime)
3716{
3717 string ret = "ERROR";
3718 switch(iTime)
3719 {
3720 case TIME_DAY: ret = "Day time"; break;
3721 case TIME_NIGHT: ret = "Night time"; break;
3722 case TIME_BOTH: ret = "Day & Night time"; break;
3723 case TIME_NONE: ret = "None"; break;
3724 case TIME_SPECIAL_APPEARANCE_NORMAL: ret = "Special - Normal Appearance"; break;
3725 case TIME_SPECIAL_APPEARANCE_SUBRACE: ret = "Special - Subrace Appearance"; break;
3726 }
3727 return ret;
3728}
3729
3730void ChangePCAppearance(object oPC, string SubraceStorage)
3731{
3732 int App = GetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + APPEARANCE_TO_CHANGE, (GetGender(oPC)==GENDER_MALE?APPEARANCE_CHANGE_MALE_FLAG:APPEARANCE_CHANGE_FEMALE_FLAG) );
3733 if(App == 0)
3734 {
3735 SSE_MessageHandler(oPC, MESSAGE_SUBRACE_APPEARANCE_DATA_ERROR);
3736 return;
3737 }
3738 if(App == GetAppearanceType(oPC))
3739 { return; }
3740 if(!DISABLE_VISUAL_EFFECTS_WHEN_CHANGING_IN_APPEARANCE)
3741 {
3742 int Alignment = GetAlignmentGoodEvil(oPC);
3743 int VFX_ID = VFX_IMP_UNSUMMON;
3744 if(Alignment == ALIGNMENT_GOOD)
3745 {
3746 VFX_ID = VFX_IMP_GOOD_HELP;
3747 }
3748 else if (Alignment == ALIGNMENT_NEUTRAL)
3749 {
3750 VFX_ID = VFX_FNF_SUMMON_MONSTER_3;
3751 }
3752 else if (Alignment == ALIGNMENT_EVIL)
3753 {
3754 VFX_ID = VFX_IMP_EVIL_HELP;
3755 }
3756 effect VisualBurst = EffectVisualEffect(VFX_ID);
3757 ApplyEffectToObject(DURATION_TYPE_TEMPORARY, VisualBurst, oPC);
3758 }
3759
3760 if(PC_SCREAMS_WHEN_CHANGING_IN_APPEARANCE)
3761 {
3762 AssignCommand(oPC, SpeakString(SUBRACE_WORDS_SPOKEN_ON_APPEARANCE_CHANGE_TO_MONSTER));
3763 }
3764 SetCreatureAppearanceType(oPC, App);
3765 if(GetAppearanceType(oPC) == App)
3766 SSE_MessageHandler(oPC, MESSAGE_SUBRACE_APPEARANCE_CHANGED);
3767}
3768
3769void ChangeToPCDefaultAppearance(object oPC)
3770{
3771 int App = GetRacialType(oPC);
3772 if(App == GetAppearanceType(oPC))
3773 { return; }
3774
3775 if(!DISABLE_VISUAL_EFFECTS_WHEN_CHANGING_IN_APPEARANCE)
3776 {
3777 int Alignment = GetAlignmentGoodEvil(oPC);
3778 int VFX_ID = VFX_IMP_UNSUMMON;
3779 if(Alignment == ALIGNMENT_GOOD)
3780 {
3781 VFX_ID = VFX_IMP_GOOD_HELP;
3782 }
3783 else if (Alignment == ALIGNMENT_NEUTRAL)
3784 {
3785 VFX_ID = VFX_FNF_SUMMON_MONSTER_3;
3786 }
3787 else if (Alignment == ALIGNMENT_EVIL)
3788 {
3789 VFX_ID = VFX_IMP_EVIL_HELP;
3790 }
3791 effect VisualBurst = EffectVisualEffect(VFX_ID);
3792 ApplyEffectToObject(DURATION_TYPE_TEMPORARY, VisualBurst, oPC);
3793 }
3794 if(PC_SCREAMS_WHEN_CHANGING_IN_APPEARANCE)
3795 {
3796 AssignCommand(oPC, SpeakString(SUBRACE_WORDS_SPOKEN_ON_APPEARANCE_CHANGE_TO_DEFAULT_RACIAL_TYPE));
3797 }
3798
3799 SetCreatureAppearanceType(oPC, App);
3800 SSE_MessageHandler(oPC, MESSAGE_SUBRACE_APPEARANCE_REVERTED);
3801}
3802
3803
3804void ApplyPermanentSubraceAppearance(int ID, object oPC)
3805{
3806 string SubraceStorage = GetSubraceStorageLocationByID(ID);
3807 int Level = GetPlayerLevel(oPC);
3808 while(Level)
3809 {
3810 string SubraceStorage1 = SubraceStorage + "_" + IntToString(Level);
3811 int iTime = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + APPEARANCE_CHANGE, TIME_FLAGS);
3812 if(iTime == TIME_BOTH)
3813 {
3814 ChangePCAppearance(oPC, SubraceStorage1);
3815 return;
3816 }
3817 Level--;
3818 }
3819 ChangeToPCDefaultAppearance(oPC);
3820}
3821
3822void ApplyTemporarySubraceAppearance(string SubraceStorage, object oPC, int iCurrentTime)
3823{
3824 int Level = GetPlayerLevel(oPC);
3825 while(Level)
3826 {
3827 string SubraceStorage1 = SubraceStorage + "_" + IntToString(Level);
3828 int iTime = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + APPEARANCE_CHANGE, TIME_FLAGS);
3829 if(iTime && iTime != TIME_NONE && iTime!= TIME_BOTH )
3830 {
3831 if(iTime == iCurrentTime)
3832 {
3833 ChangePCAppearance(oPC, SubraceStorage1);
3834 }
3835 else if(iTime != iCurrentTime)
3836 {
3837 ChangeToPCDefaultAppearance(oPC);
3838 }
3839 return;
3840 }
3841 Level--;
3842 }
3843}
3844
3845
3846
3847void ApplyPermanentSubraceSpellResistance(int ID, object oPC)
3848{
3849 string SubraceStorage = GetSubraceStorageLocationByID(ID);
3850
3851
3852 if(GetSSEInt( SubraceStorage + "_" + SUBRACE_SPELL_RESISTANCE) == 0)
3853 { return; }
3854
3855 effect iEffect = GetFirstEffect(oPC);
3856 while(GetIsEffectValid(iEffect))
3857 {
3858 int iEffectType = GetEffectType(iEffect);
3859 if(iEffectType == EFFECT_TYPE_SPELL_RESISTANCE_INCREASE ||
3860 iEffectType == EFFECT_TYPE_SPELL_RESISTANCE_DECREASE)
3861 {
3862 RemoveEffect(oPC, iEffect);
3863 }
3864 iEffect = GetNextEffect(oPC);
3865 }
3866 int SpellResAtLevel1 = GetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_SPELL_RESISTANCE, SUBRACE_SPELL_RESISTANCE_BASE_FLAGS);
3867 int SpellResAtLevelMax = GetLocalGroupFlagValue(oStorer, SubraceStorage + "_" + SUBRACE_SPELL_RESISTANCE, SUBRACE_SPELL_RESISTANCE_MAX_FLAGS);
3868 float AvgSR;
3869 effect SpellResistance;
3870 float baseSR = IntToFloat(SpellResAtLevel1);
3871 float maxSR = IntToFloat(SpellResAtLevelMax);
3872 AvgSR = maxSR - baseSR;
3873 float SRPerLevel = AvgSR/IntToFloat(MAXIMUM_PLAYER_LEVEL);
3874 float PCLevel = IntToFloat(GetPlayerLevel(oPC));
3875 float SR = (PCLevel*SRPerLevel)+ baseSR;
3876 int SR_int = FloatToInt(SR);
3877 if(SUBRACE_SPELL_RESISTANCE_STACKS)
3878 {
3879 SR_int = SR_int + GetSpellResistance(oPC);
3880
3881 }
3882 if(SR_int < 0)
3883 {
3884 SpellResistance = EffectSpellResistanceDecrease(abs(SR_int));
3885 }
3886 else
3887 {
3888 SpellResistance = EffectSpellResistanceIncrease(SR_int);
3889 }
3890 ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(SpellResistance), oPC);
3891 SSE_MessageHandler(oPC, MESSAGE_SUBRACE_SPELL_RESISTANCE_APPLIED);
3892}
3893
3894void ApplyTemporarySubraceStats(object oPC, string SubraceStorage, int iCurrentTime, int AreaUndAbove, int AreaIntExt, int AreaNatArt)
3895{
3896 int iTime = GetSSEInt( SubraceStorage + "_" + SUBRACE_STAT_MODIFIERS);
3897 iTime = iTime & ~FLAG12;
3898 if(iTime > 0)
3899 {
3900 int CurrentState = 0;
3901 if(AreaIntExt) CurrentState = CurrentState | FLAG4;
3902 if(!AreaIntExt) CurrentState = CurrentState | FLAG5;
3903 if(AreaUndAbove == AREA_UNDERGROUND) CurrentState = CurrentState | FLAG9;
3904 if(AreaUndAbove == AREA_ABOVEGROUND) CurrentState = CurrentState | FLAG8;
3905 if(AreaNatArt == AREA_NATURAL) CurrentState = CurrentState | FLAG7;
3906 if(AreaNatArt == AREA_ARTIFICIAL) CurrentState = CurrentState | FLAG6;
3907 SHA_ApplyTemporaryStats(oPC, SubraceStorage, iCurrentTime, iTime, CurrentState);
3908 }
3909}
3910
3911void TemporaryStatsVisualFX(object oPC)
3912{
3913 effect eVis = EffectVisualEffect(VFX_IMP_IMPROVE_ABILITY_SCORE);
3914 effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE);
3915 effect Vfx = EffectLinkEffects(eVis, eDur);
3916 ApplyEffectToObject(DURATION_TYPE_TEMPORARY, Vfx, oPC);
3917
3918}
3919
3920void SHA_ApplyTemporaryStats(object oPC, string SubraceStorage, int iCurrentTime, int iTime, int AreasReq/*int AreaUndAbove, int AreaIntExt, int AreaNatArt*/)
3921{
3922 string SubraceStorage1 = SubraceStorage + IntToString(iCurrentTime);
3923 int AreasCan = GetSSEInt( SubraceStorage1 + "_" + SUBRACE_STAT_MODIFIERS);
3924
3925 int CurrentStatus = GetLocalInt(oPC, SUBRACE_STATS_STATUS);
3926
3927 switch(iCurrentTime)
3928 {
3929 case TIME_DAY:
3930 {
3931 if(!(iTime & TIME_DAY) && !(iTime & TIME_NIGHT))
3932 {
3933 return;
3934 }
3935 if((CurrentStatus == TIME_SPECIAL_APPEARANCE_SUBRACE) || (CurrentStatus == TIME_SPECIAL_APPEARANCE_NORMAL))
3936 {
3937 return;
3938 }
3939 if((CurrentStatus == TIME_NIGHT) || ((CurrentStatus == TIME_DAY) && (~AreasCan & AreasReq)))
3940 {
3941 ClearSubraceTemporaryStats(oPC);
3942 SSE_MessageHandler(oPC, MESSAGE_ABILITY_SCORES_REVERTED);
3943 DeleteLocalInt(oPC, SUBRACE_STATS_STATUS);
3944 }
3945 if((iTime & TIME_DAY) && (AreasCan & AreasReq) && (CurrentStatus == TIME_DAY))
3946 {
3947 return;
3948 }
3949 break;
3950 }
3951
3952 case TIME_NIGHT:
3953 {
3954 if(!(iTime & TIME_DAY) && !(iTime & TIME_NIGHT))
3955 {
3956 return;
3957 }
3958 if((CurrentStatus == TIME_SPECIAL_APPEARANCE_SUBRACE) || (CurrentStatus == TIME_SPECIAL_APPEARANCE_NORMAL))
3959 {
3960 return;
3961 }
3962 if((CurrentStatus == TIME_DAY) || ((CurrentStatus == TIME_NIGHT) && (~AreasCan & AreasReq)))
3963 {
3964 ClearSubraceTemporaryStats(oPC);
3965 SSE_MessageHandler(oPC, MESSAGE_ABILITY_SCORES_REVERTED);
3966 DeleteLocalInt(oPC, SUBRACE_STATS_STATUS);
3967 }
3968 if((iTime & TIME_NIGHT) && (AreasCan & AreasReq) && (CurrentStatus == TIME_NIGHT))
3969 {
3970 return;
3971 }
3972 break;
3973 }
3974
3975 case TIME_SPECIAL_APPEARANCE_SUBRACE:
3976 {
3977 //appearance ability score takes priority...
3978 //normal appearance ability score takes priority...
3979 if((CurrentStatus == TIME_SPECIAL_APPEARANCE_NORMAL) || (CurrentStatus == TIME_DAY) || (CurrentStatus == TIME_NIGHT) || (~AreasCan & AreasReq))
3980 {
3981 ClearSubraceTemporaryStats(oPC);
3982 SSE_MessageHandler(oPC, ((CurrentStatus & TIME_SPECIAL_APPEARANCE_NORMAL)?MESSAGE_ABILITY_SCORES_APPEARANCE_TRIGGERED_REVERTED:MESSAGE_ABILITY_SCORES_REVERTED));
3983 DeleteLocalInt(oPC, SUBRACE_STATS_STATUS);
3984 }
3985 //appearance is not normal, area requirements are met, and status says the stats have been applied, then return;
3986 CurrentStatus = GetLocalInt(oPC, SUBRACE_STATS_STATUS);
3987 if((GetAppearanceType(oPC) != SHA_GetDefaultAppearanceType(oPC)) && (AreasReq & AreasCan) && (CurrentStatus == TIME_SPECIAL_APPEARANCE_SUBRACE))
3988 {
3989 return;
3990 }
3991 if(!(iTime & TIME_SPECIAL_APPEARANCE_SUBRACE))
3992 {
3993 return;
3994 }
3995 break;
3996 }
3997 case TIME_SPECIAL_APPEARANCE_NORMAL:
3998 {
3999 //normal appearance ability score takes priority...
4000 if((CurrentStatus == TIME_SPECIAL_APPEARANCE_SUBRACE) || (CurrentStatus == TIME_DAY) || (CurrentStatus == TIME_NIGHT) || (~AreasCan & AreasReq))
4001 {
4002 ClearSubraceTemporaryStats(oPC);
4003 SSE_MessageHandler(oPC, ((CurrentStatus == TIME_SPECIAL_APPEARANCE_SUBRACE)?MESSAGE_ABILITY_SCORES_APPEARANCE_TRIGGERED_REVERTED:MESSAGE_ABILITY_SCORES_REVERTED));
4004 DeleteLocalInt(oPC, SUBRACE_STATS_STATUS);
4005 }
4006 if((GetAppearanceType(oPC) == SHA_GetDefaultAppearanceType(oPC)) && (AreasReq & AreasCan) && (CurrentStatus == iCurrentTime))
4007 {
4008 return;
4009 }
4010 if(!(iTime & TIME_SPECIAL_APPEARANCE_NORMAL))
4011 {
4012 return;
4013 }
4014 break;
4015 }
4016 }
4017
4018 if(!(iTime & iCurrentTime))
4019 {
4020 return;
4021 }
4022 if((~AreasCan & AreasReq))
4023 {
4024 return;
4025 }
4026
4027 SetLocalInt(oPC, SUBRACE_STATS_STATUS, iCurrentTime);
4028 int iType = GetSSEInt( SubraceStorage + IntToString(iCurrentTime) + "_" + SUBRACE_STAT_MODIFIER_TYPE);
4029 SubraceStorage = SubraceStorage + IntToString(iCurrentTime);
4030 if(GetIsResting(oPC))
4031 {
4032 AssignCommand(oPC, ClearAllActions(TRUE));
4033 }
4034 ClearSubraceTemporaryStats(oPC);
4035 if(iType == SUBRACE_STAT_MODIFIER_TYPE_PERCENTAGE)
4036 {
4037 AssignCommand(oPC, ApplySubraceBonusStatsByPercentage(oPC, SubraceStorage));
4038 }
4039 else if(iType == SUBRACE_STAT_MODIFIER_TYPE_POINTS)
4040 {
4041 AssignCommand(oPC, ApplySubraceBonusStatsByPoints(oPC, SubraceStorage));
4042 }
4043 //STAT MODIFIER TYPE Unrecognised
4044 else return;
4045 DelayCommand(1.0*SSE_LOAD_FACTOR, TemporaryStatsVisualFX(oPC));
4046 DelayCommand(1.0*SSE_LOAD_FACTOR, SSE_MessageHandler(oPC, MESSAGE_ABILITY_SCORES_CHANGED) );
4047
4048}
4049
4050
4051void ClearSubraceEffects(object oPC)
4052{
4053 effect eBad = GetFirstEffect(oPC);
4054 while(GetIsEffectValid(eBad))
4055 {
4056 int iType = GetEffectType(eBad);
4057 //Remove effect if it is a subracial effect
4058 if(GetEffectCreator(eBad) == oStorer &&
4059 ( GetEffectSubType(eBad) == SUBTYPE_SUPERNATURAL) ||
4060 ( iType == EFFECT_TYPE_VISUALEFFECT ) )
4061 {
4062 if (iType == EFFECT_TYPE_ARCANE_SPELL_FAILURE ||
4063 iType == EFFECT_TYPE_BLINDNESS ||
4064 iType == EFFECT_TYPE_CHARMED ||
4065 iType == EFFECT_TYPE_CONCEALMENT ||
4066 iType == EFFECT_TYPE_CONFUSED ||
4067 iType == EFFECT_TYPE_CUTSCENEGHOST ||
4068 iType == EFFECT_TYPE_HASTE ||
4069 iType == EFFECT_TYPE_IMMUNITY ||
4070 iType == EFFECT_TYPE_IMPROVEDINVISIBILITY ||
4071 iType == EFFECT_TYPE_INVISIBILITY ||
4072 iType == EFFECT_TYPE_MISS_CHANCE ||
4073 iType == EFFECT_TYPE_MOVEMENT_SPEED_DECREASE ||
4074 iType == EFFECT_TYPE_MOVEMENT_SPEED_INCREASE ||
4075 iType == EFFECT_TYPE_POLYMORPH ||
4076 iType == EFFECT_TYPE_REGENERATE ||
4077 iType == EFFECT_TYPE_SANCTUARY ||
4078 iType == EFFECT_TYPE_SLOW ||
4079 iType == EFFECT_TYPE_TEMPORARY_HITPOINTS ||
4080 iType == EFFECT_TYPE_TRUESEEING ||
4081 iType == EFFECT_TYPE_ULTRAVISION ||
4082 iType == EFFECT_TYPE_VISUALEFFECT ||
4083 iType == EFFECT_TYPE_DAMAGE_IMMUNITY_INCREASE ||
4084 iType == EFFECT_TYPE_DAMAGE_IMMUNITY_DECREASE)
4085 {
4086
4087 RemoveEffect(oPC, eBad);
4088 }
4089 }
4090 eBad = GetNextEffect(oPC);
4091 }
4092}
4093
4094void ClearSubraceTemporaryStats(object oPC)
4095{
4096 effect eBad = GetFirstEffect(oPC);
4097 while(GetIsEffectValid(eBad))
4098 {
4099 int iType = GetEffectType(eBad);
4100
4101 if (iType == EFFECT_TYPE_ABILITY_DECREASE ||
4102 iType == EFFECT_TYPE_ABILITY_INCREASE ||
4103 iType == EFFECT_TYPE_AC_DECREASE ||
4104 iType == EFFECT_TYPE_AC_INCREASE ||
4105 iType == EFFECT_TYPE_ATTACK_INCREASE ||
4106 iType == EFFECT_TYPE_ATTACK_DECREASE ||
4107 iType == EFFECT_TYPE_SPELL_RESISTANCE_DECREASE ||
4108 iType == EFFECT_TYPE_SPELL_RESISTANCE_INCREASE ||
4109 iType == EFFECT_TYPE_SAVING_THROW_DECREASE)
4110 {
4111 //Remove effect if it is a subracial effect
4112 if(GetEffectSubType(eBad) == SUBTYPE_SUPERNATURAL)
4113 {
4114 if(GetEffectCreator(eBad) == oPC)
4115 {
4116 RemoveEffect(oPC, eBad);
4117 }
4118 }
4119 }
4120 eBad = GetNextEffect(oPC);
4121 }
4122}
4123
4124void ApplySubraceBonusStatsByPoints(object oPC, string SubraceStorage)
4125{
4126int i=0;
4127for( ; i < 6 ; i++)
4128 {
4129 float statMod = GetLocalFloat(oStorer, SubraceStorage + "_" + GetSubraceStatStorageName(i, FALSE) );
4130 if(statMod != 0.0)
4131 {
4132 ApplyStat_AbilityByPoints(i, statMod, oPC);
4133 }
4134 }
4135 float ABMod = GetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_STAT_AB_MODIFIER);
4136 float ACMod = GetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_STAT_AC_MODIFIER);
4137
4138 if(ABMod != 0.0)
4139 {
4140 ApplyAttackBonusByPoints(ABMod, oPC);
4141 }
4142 if(ACMod != 0.0)
4143 {
4144 ApplyArmourClassBonusByPoints(ACMod, oPC);
4145 }
4146}
4147
4148void ApplyStat_AbilityByPoints(int AbilityToMod, float points, object oPC)
4149{
4150 int StatIncrease = FloatToInt(points);
4151 effect StatEffect;
4152 if(StatIncrease > 0)
4153 {
4154 StatEffect = EffectAbilityIncrease(AbilityToMod, StatIncrease);
4155 }
4156 else if(StatIncrease < 0)
4157 {
4158 int StatIncrease1 = abs(StatIncrease);
4159 StatEffect = EffectAbilityDecrease(AbilityToMod, StatIncrease1);
4160 }
4161 ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(StatEffect), oPC);
4162 }
4163
4164void ApplyAttackBonusByPoints(float points, object oPC)
4165{
4166 int ABChange = FloatToInt(points);
4167 effect StatEffect;
4168 effect StatEffect1;
4169 if(ABChange > 0)
4170 {
4171 StatEffect = EffectAttackIncrease(ABChange, ATTACK_BONUS_ONHAND);
4172 StatEffect1 = EffectAttackIncrease(ABChange, ATTACK_BONUS_OFFHAND);
4173 }
4174 else if(ABChange < 0)
4175 {
4176 int ABChange1 = abs(ABChange);
4177 StatEffect = EffectAttackDecrease(ABChange1, ATTACK_BONUS_ONHAND);
4178 StatEffect1 = EffectAttackDecrease(ABChange1, ATTACK_BONUS_OFFHAND);
4179 }
4180 ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(StatEffect), oPC);
4181 ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(StatEffect1), oPC);
4182}
4183
4184void ApplyArmourClassBonusByPoints(float points, object oPC)
4185{
4186 int ACChange = FloatToInt(points);
4187 effect StatEffect;
4188 if(ACChange > 0)
4189 {
4190 StatEffect = EffectACIncrease(ACChange, AC_NATURAL_BONUS);
4191 }
4192 else if(ACChange < 0)
4193 {
4194 int ACChange1 = abs(ACChange);
4195 StatEffect = EffectACDecrease(ACChange1, AC_NATURAL_BONUS);
4196 }
4197 ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(StatEffect), oPC);
4198}
4199
4200void ApplySubraceBonusStatsByPercentage(object oPC, string SubraceStorage)
4201{
4202int i=0;
4203for( ; i < 6 ; i++)
4204 {
4205 float statMod = GetLocalFloat(oStorer, SubraceStorage + "_" + GetSubraceStatStorageName(i, FALSE) );
4206 if(statMod != 0.0)
4207 {
4208 ApplyStat_AbilityByPercentage(i, statMod, oPC);
4209 }
4210 }
4211 float ABMod = GetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_STAT_AB_MODIFIER);
4212 float ACMod = GetLocalFloat(oStorer, SubraceStorage + "_" + SUBRACE_STAT_AC_MODIFIER);
4213
4214 if(ABMod != 0.0)
4215 {
4216 ApplyAttackBonusByPercentage(ABMod, oPC);
4217 }
4218 if(ACMod != 0.0)
4219 {
4220 ApplyArmourClassBonusByPercentage(ACMod, oPC);
4221 }
4222}
4223
4224void ApplyStat_AbilityByPercentage(int AbilityToMod, float percentage, object oPC)
4225{
4226 int currentStat = GetAbilityScore(oPC, AbilityToMod);
4227 float cStat = IntToFloat(currentStat);
4228
4229 float Stat = cStat*percentage;
4230 int newStat = FloatToInt(Stat);
4231 effect StatEffect;
4232 if(newStat > 0)
4233 {
4234 StatEffect = EffectAbilityIncrease(AbilityToMod, newStat);
4235 }
4236 else if(newStat < 0)
4237 {
4238 int newStat1 = abs(newStat);
4239 StatEffect = EffectAbilityDecrease(AbilityToMod, newStat1);
4240 }
4241 ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(StatEffect), oPC);
4242}
4243
4244void ApplyAttackBonusByPercentage(float percentage, object oPC)
4245{
4246 float currentAB = IntToFloat(GetBaseAttackBonus(oPC));
4247 int Neg = FALSE;
4248 int Neg2 = FALSE;
4249 if(currentAB < 0.0 ) { Neg = TRUE; }
4250 if(percentage < 0.0 ) { Neg2 = TRUE; }
4251 int newAB = FloatToInt(currentAB*percentage);
4252 if(Neg && Neg2 ) { newAB = -newAB; }
4253 effect StatEffect;
4254 effect StatEffect1;
4255 if(newAB > 0)
4256 {
4257 StatEffect = EffectAttackIncrease(newAB, ATTACK_BONUS_ONHAND);
4258 StatEffect1 = EffectAttackIncrease(newAB, ATTACK_BONUS_OFFHAND);
4259 }
4260 else if(newAB < 0)
4261 {
4262 int newAB1 = abs(newAB);
4263 StatEffect = EffectAttackDecrease(newAB1, ATTACK_BONUS_ONHAND);
4264 StatEffect1 = EffectAttackDecrease(newAB1, ATTACK_BONUS_OFFHAND);
4265 }
4266 ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(StatEffect), oPC);
4267 ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(StatEffect1), oPC);
4268}
4269
4270void ApplyArmourClassBonusByPercentage(float percentage, object oPC)
4271{
4272 float currentAC = IntToFloat(GetAC(oPC));
4273 int newAC = FloatToInt(currentAC*percentage);
4274 effect StatEffect;
4275 if(newAC > 0)
4276 {
4277 StatEffect = EffectACIncrease(newAC, AC_NATURAL_BONUS, AC_VS_DAMAGE_TYPE_ALL);
4278 }
4279 else if(newAC < 0)
4280 {
4281 int newAC1 = abs(newAC);
4282 StatEffect = EffectACDecrease(newAC1, AC_NATURAL_BONUS, AC_VS_DAMAGE_TYPE_ALL);
4283 }
4284 ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(StatEffect), oPC);
4285}
4286
4287
4288
4289void SHA_SubraceForceUnequipItem(object oItem)
4290{
4291 ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectCutsceneImmobilize(), OBJECT_SELF, 0.1);
4292 ClearAllActions(TRUE);
4293 ActionUnequipItem(oItem);
4294 ActionDoCommand(SetCommandable(TRUE));
4295 SetCommandable(FALSE);
4296}
4297
4298void SHA_SubraceForceEquipItem(object oItem, int InvoSlot)
4299{
4300 ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectCutsceneImmobilize(), OBJECT_SELF, 0.1);
4301 ClearAllActions(TRUE);
4302 ActionEquipItem(oItem, InvoSlot);
4303 ActionDoCommand(SetCommandable(TRUE));
4304 SetCommandable(FALSE);
4305}
4306
4307
4308void CheckCanUseItem(object oItem, object oPC, int iType = 1)
4309{
4310 int ID = GetPlayerSubraceID(oPC);
4311 if(!ID || !GetIsObjectValid(oItem))
4312 { return; }
4313 //ingore creature items.
4314 switch(GetBaseItemType(oItem))
4315 {
4316 case BASE_ITEM_CPIERCWEAPON:
4317 case BASE_ITEM_CSLASHWEAPON:
4318 case BASE_ITEM_CSLSHPRCWEAP:
4319 case BASE_ITEM_CBLUDGWEAPON:
4320 case BASE_ITEM_CREATUREITEM: return;
4321 }
4322 string SubraceStorage = GetSubraceStorageLocationByID(ID) + "_" + SUBRACE_ITEM_RESTRICTION + "_";
4323
4324 int Restrictions;
4325 int Time = SHA_GetCurrentTime();
4326
4327
4328 if(SHA_GetDefaultAppearanceType(oPC) == GetAppearanceType(oPC))
4329 {
4330 //Normal form
4331 Restrictions = GetSSEInt( SubraceStorage + IntToString(TIME_SPECIAL_APPEARANCE_NORMAL) );
4332 }
4333 else
4334 {
4335 //Special form
4336 Restrictions = GetSSEInt( SubraceStorage + IntToString(TIME_SPECIAL_APPEARANCE_SUBRACE) );
4337 }
4338
4339//No Special Restrictions based on appearance, try loading a time-based one!
4340if(!Restrictions)
4341 {
4342 Restrictions = GetSSEInt( SubraceStorage + IntToString(Time) );
4343 }
4344
4345//If no restrictions at all for the current time and form, Restrictions will be FALSE
4346 if(Restrictions)
4347 {
4348 if(SHA_TestItemReq(GetItemType(oItem), Restrictions))
4349 {
4350 string sMsg;
4351 switch(iType)
4352 {
4353 case 1: sMsg = "weapon"; break;
4354 case 2: sMsg = "armor (or shield)"; break;
4355 case 3: sMsg = "jewlery (or misc item)"; break;
4356 default: sMsg = "item"; break;
4357 }
4358 SSE_MessageHandler(oPC, MESSAGE_SUBRACE_CANNOT_EQUIP_ITEM, sMsg);
4359 DelayCommand(0.3*SSE_LOAD_FACTOR, AssignCommand(oPC, SHA_SubraceForceUnequipItem(oItem)));
4360 }
4361 }
4362
4363}
4364
4365
4366void SubraceOnPlayerEquipItem()
4367{
4368 object oItem = GetPCItemLastEquipped();
4369 object oPC = GetPCItemLastEquippedBy();
4370 if(!GetPlayerSubraceID(oPC) || GetIsSSEDisabled()) return;
4371
4372 int iType = 1;
4373 switch(GetBaseItemType(oItem))
4374 {
4375 case BASE_ITEM_ARMOR:
4376 case BASE_ITEM_HELMET:
4377 case BASE_ITEM_LARGESHIELD:
4378 case BASE_ITEM_SMALLSHIELD:
4379 case BASE_ITEM_TOWERSHIELD: iType = 2; break;
4380 case BASE_ITEM_RING:
4381 case BASE_ITEM_AMULET:
4382 case BASE_ITEM_CLOAK:
4383 case BASE_ITEM_GLOVES:
4384 case BASE_ITEM_BRACER: iType = 3; break;
4385 }
4386 CheckCanUseItem(oItem, oPC, iType);
4387}
4388
4389void CheckIfCanUseEquipedWeapon(object oPC)
4390{
4391 if(!GetPlayerSubraceID(oPC)) return;
4392
4393 object Wep1 = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC);
4394 object Wep2 = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC);
4395 CheckCanUseItem (Wep1, oPC, 1);
4396 DelayCommand(3.0*SSE_LOAD_FACTOR, CheckCanUseItem (Wep2, oPC, 1));
4397}
4398
4399void CheckIfCanUseEquippedArmor(object oPC)
4400{
4401 if(!GetPlayerSubraceID(oPC))
4402 { return; }
4403
4404 object oItem = GetItemInSlot(INVENTORY_SLOT_CHEST, oPC);
4405 CheckCanUseItem(oItem, oPC, 2);
4406}
4407
4408string GetSubraceNameByID(int ID, int Lowercase=FALSE)
4409{
4410 string Name=GetLocalString(oStorer, MODULE_SUBRACE_NUMBER + IntToString(ID) );
4411 return Lowercase?GetStringLowerCase(Name):Name;
4412}
4413
4414string GetSubraceNameByAlias(string Alias, int Lowercase=FALSE)
4415{
4416 //Aliases have same ID as the Subrace, however only the base name
4417 // is recorded at the "Subrace-Index"
4418 return GetSubraceNameByID(GetSubraceID(Alias), Lowercase );
4419}
4420
4421// 3.0.6.11 - moon: Now this case bug is fixed and stays fixed!
4422void InitiateSubraceChecking(object oPC) {
4423 // No lowercase on the alias.
4424 // we use it to print later in LoadSubraceInfoOnPC and it
4425 // is smart enough to lowercase when needed!
4426 string subraceAlias = GetSubRace(oPC);
4427 string subraceCased = GetSubraceNameByAlias(subraceAlias);
4428 string subrace = GetStringLowerCase(subraceCased);
4429
4430 //3.0.6.5 - added default race changes
4431 if(subrace == "") {
4432 // no sub-race
4433 if (USE_SSE_DEFAULT_RACES) {
4434 // use default sub-race
4435 // Assume that there is no previously stored cased value.
4436 // Even if there is, it will be moved next time.
4437 // Of course it might have been a reject, but
4438 // if there is a restriction on default sub-races
4439 // then how are they a default?
4440 CheckAndApplyDefaultSubrace(oPC);
4441 subraceAlias = GetSubRace(oPC);
4442 subrace = GetSubraceNameByAlias(subraceAlias);
4443 } else {
4444 // no default sub-race means nothing to do.
4445 return;
4446 }
4447 } else if(subrace == subraceCased){
4448 // The sub-race name is already lower-case.
4449 // empty subraceCased to save ourselves an extra call to the DB.
4450 subraceCased = "";
4451 }
4452
4453 if(subrace != "") {
4454 //3.0.6.9 fix + 3.0.6.11 refix
4455 int check1 = SUBRACE_UNINITIALIZED;
4456 if(subraceCased != "") {
4457 // We got two different casing... try the mixed case first.
4458 check1 = GetSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + "_" + subraceCased, oPC);
4459 if(check1 != SUBRACE_UNINITIALIZED) {
4460 // There was a value with mixed-case, move it to the lowercase location.
4461 // and remove the mixed-case entry.
4462 SetSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + "_" + subrace, check1, oPC);
4463 DeleteSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + "_" + subraceCased, oPC);
4464 }
4465 }
4466
4467 if(check1 == SUBRACE_UNINITIALIZED){
4468 // This happens if A) subraceCased was all lowercase or
4469 // B) There was no value stored in the database for subraceCased.
4470 check1 = GetSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + "_" + subrace, oPC);
4471 }
4472 if(check1 == SUBRACE_REJECTED){
4473 //Rejected so stop here.
4474 return;
4475 }
4476 if(check1 == SUBRACE_UNINITIALIZED) {
4477 int check2 = CheckIfPCMeetsAnySubraceCriteria(oPC);
4478 if(check2 == SUBRACE_UNRECOGNISED) {
4479 return;
4480 } else if(!check2) {
4481 SetSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + "_" + subrace, SUBRACE_REJECTED, oPC);
4482 return;
4483 }
4484 // Since there is return in the two previous branches, we do not need else if here.
4485 SetSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + "_" + subrace, SUBRACE_ACCEPTED, oPC);
4486 }
4487
4488 // At this point - sub-race is accepted and the database is updated if needed!
4489 if(SEARCH_AND_DESTROY_SKINS_IN_INVENTORY) {
4490 SearchAndDestroySkinsAndClaws(oPC);
4491 }
4492 DelayCommand(1.0*SSE_LOAD_FACTOR, LoadSubraceInfoOnPC(oPC, subraceAlias));
4493//b13
4494 if (USE_SSE_SUBRACE_START)
4495 {
4496 DelayCommand(22.0*SSE_LOAD_FACTOR, Subrace_MoveToStartLocation(oPC, subraceAlias));
4497 }
4498//end b13
4499 }
4500}
4501
4502void Subrace_MoveToStartLocation(object oPC, string subrace = "")
4503{
4504// 3.0.6.5
4505 if (subrace == "")
4506 {
4507 string subrace = GetSubraceNameByAlias(GetSubRace(oPC));
4508 }
4509 string SubraceStorage = GetSubraceStorageLocation(subrace);
4510 string WPTag = GetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_START_LOCATION);
4511 object oWP = GetWaypointByTag(WPTag);
4512 if( GetIsObjectValid(oWP) )
4513 {
4514 DelayCommand(0.5*SSE_LOAD_FACTOR, AssignCommand(oPC, JumpToLocation(GetLocation(oWP))));
4515 DelayCommand(0.5*SSE_LOAD_FACTOR, SSE_MessageHandler(oPC, MESSAGE_SUBRACE_MOVE_TO_START_LOCATION, CapitalizeString(subrace)) );
4516 }
4517}
4518
4519//3.0.6.4
4520//3.0.6.5 fix - string subrace removed
4521void Subrace_MoveToDeathLocation(object oPC)
4522{
4523 string subraceAlias = GetSubRace(oPC);
4524 string subrace = GetSubraceNameByAlias(subraceAlias, TRUE);
4525 string SubraceStorage = GetSubraceStorageLocation(subrace);
4526 string WPTag = GetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_DEATH_LOCATION);
4527 object oWP = GetWaypointByTag(WPTag);
4528 object oDefaultWP = GetWaypointByTag(SUBRACE_DEATH_DEFAULT);
4529 if( GetIsObjectValid(oWP) )
4530 {
4531 DelayCommand(0.5*SSE_LOAD_FACTOR, AssignCommand(oPC, JumpToLocation(GetLocation(oWP))));
4532 }
4533 else
4534 {
4535//3.0.6.5 fix - defaults to GetStartingLocation()
4536 if( GetIsObjectValid(oWP) )
4537 {
4538 DelayCommand(0.5*SSE_LOAD_FACTOR, AssignCommand(oPC, JumpToLocation(GetLocation(oDefaultWP))));
4539 }
4540 else
4541 {
4542 DelayCommand(0.5*SSE_LOAD_FACTOR, AssignCommand(oPC, JumpToLocation(GetStartingLocation())));
4543 }
4544 }
4545
4546}
4547
4548void ChangeSubraceFactions(object oPC, string subrace)
4549{
4550 string SubraceStorage = GetSubraceStorageLocation(subrace);
4551 int Count = GetSSEInt( SubraceStorage + "_" + SUBRACE_FACTION_COUNT);
4552 if(Count)
4553 {
4554 float fDelay;
4555 while(Count != 0)
4556 {
4557 fDelay += 0.10;
4558 string FactionCreatureTag = GetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_FACTION_CREATURE + "_" + IntToString(Count));
4559 int Reputation = GetSSEInt( SubraceStorage + "_" + SUBRACE_FACTION_REPUTATION + "_" + IntToString(Count));
4560 DelayCommand(fDelay*SSE_LOAD_FACTOR, Subrace_FactionAdjustment(oPC, FactionCreatureTag, Reputation));
4561 Count--;
4562 }
4563 SHA_SendSubraceMessageToPC(oPC, SSE_GetStandardMessage(MESSAGE_SUBRACE_FACTION_ADJUSTED), FALSE);
4564 }
4565
4566}
4567
4568void Subrace_FactionAdjustment(object oPC, string FactionTag, int Adjustment)
4569{
4570 object Faction = GetObjectByTag(FactionTag);
4571 if( GetIsObjectValid(Faction) )
4572 {
4573 ClearPersonalReputation(oPC, Faction);
4574 ClearPersonalReputation(Faction, oPC);
4575 //Make friendly first..
4576 AdjustReputation(oPC, Faction, 100);
4577
4578 //Now adjust
4579 AdjustReputation(oPC, Faction, Adjustment);
4580 }
4581
4582}
4583
4584void CheckAndSwitchSubrace(object oPC)
4585{
4586 string subrace = GetStringLowerCase(GetSubRace(oPC));
4587
4588// 3.0.6.5
4589 if(subrace == "")
4590 {
4591 if (USE_SSE_DEFAULT_RACES)
4592 {
4593 CheckAndApplyDefaultSubrace(oPC);
4594 subrace = GetStringLowerCase(GetSubRace(oPC));
4595 }
4596 else { return; }
4597 }
4598
4599 string SubraceStorage = GetSubraceStorageLocation(subrace);
4600 int Level = GetPlayerLevel(oPC);
4601 string switchSubraceNames = GetLocalString(oStorer, SubraceStorage + "_" + SUBRACE_SWITCH_NAME + IntToString(Level));
4602 if(switchSubraceNames != "")
4603 {
4604 while(switchSubraceNames != "")
4605 {
4606 int iPos = FindSubString(switchSubraceNames, "_");
4607 string sSubrace;
4608 if(iPos != -1)
4609 {
4610 sSubrace = GetStringLeft(switchSubraceNames, iPos);
4611 }
4612 else
4613 {
4614 sSubrace = switchSubraceNames;
4615 }
4616 switchSubraceNames = GetStringRight(switchSubraceNames, GetStringLength(switchSubraceNames) - iPos - 1);
4617 string CurrentSubrace = GetSubRace(oPC);
4618 string NewSubrace = sSubrace;
4619 //SetSubRace(oPC, NewSubrace);
4620 //subrace = GetStringLowerCase(GetSubRace(oPC));
4621 SSE_MessageHandler(oPC, MESSAGE_SUBRACE_SWITCH_CHECKING_REQUIREMENTS, NewSubrace);
4622
4623
4624 int check = FALSE;
4625 int NeedToMeetRequirements = GetSSEInt( SubraceStorage + "_" + SUBRACE_SWITCH_MUST_MEET_REQUIREMENTS + IntToString(Level));
4626 //only check restrictions if need be.
4627 if(NeedToMeetRequirements)
4628 {
4629 check = CheckIfPCMeetsAnySubraceCriteria(oPC);
4630 }
4631 if(!check)
4632 {
4633 subrace = GetStringLowerCase(NewSubrace);
4634 SetSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + "_" + subrace, SUBRACE_ACCEPTED, oPC);
4635 DeleteSubraceInfoOnPC(oPC);
4636
4637 DelayCommand(4.2*SSE_LOAD_FACTOR, SSE_MessageHandler(oPC, MESSAGE_SUBRACE_SWITCHING, NewSubrace + "..."));
4638 DelayCommand(4.3*SSE_LOAD_FACTOR, SetSubRace(oPC, NewSubrace));
4639 DelayCommand(5.1*SSE_LOAD_FACTOR, LoadSubraceInfoOnPC(oPC, NewSubrace));
4640 DelayCommand(15.0*SSE_LOAD_FACTOR, CheckIfCanUseEquipedWeapon(oPC));
4641 DelayCommand(18.5*SSE_LOAD_FACTOR, CheckIfCanUseEquippedArmor(oPC));
4642 DelayCommand(21.5*SSE_LOAD_FACTOR, SSE_MessageHandler(oPC, MESSAGE_SUBRACE_SWITCHED));
4643 return;
4644 }
4645 }
4646 }
4647}
4648
4649void ModifyAttachments(object oPC, string SubraceStorage, int Level)
4650{
4651 string script = "";
4652 string SubraceStorage1 = SubraceStorage + "_" + IntToString(Level);
4653 if(GetSSEInt( SubraceStorage1 + "_" + SUBRACE_ATTACHMENT_FLAGS) )
4654 {
4655 int Gender = GetGender(oPC);
4656 int Wings = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + SUBRACE_ATTACHMENT_FLAGS, (Gender==GENDER_MALE?SUBRACE_ATTACHMENT_FLAGS_WINGS_MALE:SUBRACE_ATTACHMENT_FLAGS_WINGS_FEMALE ) );
4657 int Tail = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + SUBRACE_ATTACHMENT_FLAGS, (Gender==GENDER_MALE?SUBRACE_ATTACHMENT_FLAGS_TAIL_MALE:SUBRACE_ATTACHMENT_FLAGS_TAIL_FEMALE ) );
4658 if(Wings) { SetCreatureWingType(Wings, oPC); SSE_MessageHandler(oPC, MESSAGE_SUBRACE_NEW_WINGS_GAINED);}
4659 if(Tail) { SetCreatureTailType(Tail, oPC); SSE_MessageHandler(oPC, MESSAGE_SUBRACE_NEW_TAIL_GAINED); }
4660 }
4661}
4662
4663void ModifyPortrait(object oPC, string SubraceStorage, int Level)
4664{
4665 string SubraceStorage1 = SubraceStorage + "_" + IntToString(Level);
4666 string Gender = (GetGender(oPC)==GENDER_MALE?SUBRACE_PORTRAIT_MALE:SUBRACE_PORTRAIT_FEMALE);
4667 string Portrait = GetLocalString(oStorer, SubraceStorage1 + "_" + SUBRACE_PORTRAIT + "_" + Gender);
4668 if(Portrait != "")
4669 {
4670 SetPortraitResRef(oPC, Portrait);
4671 SSE_MessageHandler(oPC, MESSAGE_SUBRACE_NEW_PORTRAIT_GAINED);
4672 }
4673}
4674
4675void ChangeMiscellaneousSubraceStuff(object oPC, int Level)
4676{
4677 string SubraceStorage = GetSubraceStorageLocationByID(GetPlayerSubraceID(oPC));
4678 ModifyAttachments(oPC, SubraceStorage, Level);
4679 ModifyPortrait(oPC, SubraceStorage, Level);
4680}
4681
4682void SubraceOnPlayerLevelUp()
4683{
4684 object oPC = GetPCLevellingUp();
4685 if(!GetPlayerSubraceID(oPC))
4686 {
4687 return;
4688 }
4689 if(GetIsSSEDisabled())
4690 {
4691 SSE_MessageHandler(oPC, MESSAGE_SUBRACE_SSE_IS_SHUTDOWN);
4692 return;
4693 }
4694
4695 int Level = GetPlayerLevel(oPC);
4696 ReapplySubraceAbilities(oPC);
4697 DelayCommand(2.5*SSE_LOAD_FACTOR, ChangeMiscellaneousSubraceStuff(oPC, Level));
4698
4699 DelayCommand(2.0*SSE_LOAD_FACTOR, CheckAndGiveSubraceItems(oPC));
4700 int NeedsToRelog = CheckForLetoReLog(oPC, Level);
4701 if(NeedsToRelog)
4702 {
4703 if(!LETO_ACTIVATE_PORTAL)
4704 {
4705 DelayCommand(5.0*SSE_LOAD_FACTOR, PopUpDeathGUIPanel(oPC, FALSE, FALSE, 0, SUBRACE_ENGINE + SSE_GetStandardMessage(MESSAGE_LETO_PLEASE_RELOG)));
4706 if(LETO_AUTOMATICALLY_BOOT)
4707 {
4708 DelayCommand(5.2*SSE_LOAD_FACTOR, SSE_MessageHandler(oPC, MESSAGE_LETO_AUTOBOOT, IntToString(LETO_AUTOMATIC_BOOT_DELAY)));
4709 DelayCommand((5.2*SSE_LOAD_FACTOR) + IntToFloat(LETO_AUTOMATIC_BOOT_DELAY), DelayBoot(oPC));
4710 }
4711 }
4712 else
4713 {
4714 if(!LETO_PORTAL_KEEP_CHARACTER_IN_THE_SAME_PLACE)
4715 {
4716 DelayCommand(5.2*SSE_LOAD_FACTOR, SSE_MessageHandler(oPC, MESSAGE_LETO_AUTOPORTAL, IntToString(LETO_AUTOMATIC_PORTAL_DELAY)));
4717//b13 fix
4718 DelayCommand(5.2*SSE_LOAD_FACTOR + IntToFloat(LETO_AUTOMATIC_PORTAL_DELAY), ActivatePortal(oPC, LETO_PORTAL_IP_ADDRESS, LETO_PORTAL_SERVER_PASSWORD, LETO_PORTAL_WAYPOINT, TRUE));
4719 }
4720 else
4721 {
4722 int RandomNumber = d100(1);
4723 string sWPTag = "WP_SUBRACE_P" + IntToString(RandomNumber);
4724 object oWaypoint = CreateObject(OBJECT_TYPE_WAYPOINT, "nw_waypoint001", GetLocation(oPC), FALSE, sWPTag);
4725 DelayCommand(5.2*SSE_LOAD_FACTOR, SSE_MessageHandler(oPC, MESSAGE_LETO_DONT_PANIC_JUSTPORTING));
4726//b13 fix
4727 DelayCommand(5.2*SSE_LOAD_FACTOR + IntToFloat(LETO_AUTOMATIC_PORTAL_DELAY), ActivatePortal(oPC, LETO_PORTAL_IP_ADDRESS, LETO_PORTAL_SERVER_PASSWORD, sWPTag, TRUE));
4728 DelayCommand(15.0*SSE_LOAD_FACTOR + IntToFloat(LETO_AUTOMATIC_PORTAL_DELAY), DestroyObject(oWaypoint, 0.1));
4729 }
4730 }
4731
4732 DelayCommand(5.0*SSE_LOAD_FACTOR, SetSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + LETO_CHANGES_MADE_FOR_THIS_LEVEL + "_" + GetStringLowerCase(GetSubRace(oPC)), Level, oPC));
4733 }
4734 DelayCommand(5.0*SSE_LOAD_FACTOR, CheckAndSwitchSubrace(oPC));
4735}
4736
4737string LetoSubraceModifications(object oPC, string SubraceStorage, int Level, int LastLetoLevelChanges)
4738{
4739 string ScriptForLeto = "";
4740 LastLetoLevelChanges++;
4741 while(LastLetoLevelChanges <= Level)
4742 {
4743 ScriptForLeto += CheckAndModifyBaseStats(oPC, SubraceStorage, LastLetoLevelChanges);
4744 ScriptForLeto += CheckAndModifyFeats(oPC, SubraceStorage, LastLetoLevelChanges);
4745 ScriptForLeto += CheckAndModifySoundSet(oPC, SubraceStorage, LastLetoLevelChanges);
4746 ScriptForLeto += CheckAndModifySkills(oPC, SubraceStorage, LastLetoLevelChanges);
4747 //3.0.6.6
4748 // ScriptForLeto += CheckAndModifyColors(oPC, SubraceStorage, LastLetoLevelChanges);
4749 LastLetoLevelChanges++;
4750 }
4751 return ScriptForLeto;
4752}
4753
4754int CheckForLetoReLog(object oPC, int Level)
4755{
4756 if(!ENABLE_LETO)
4757 { return FALSE; }
4758
4759 //Need lowercase sub-race name for database.
4760 string subrace = GetStringLowerCase(GetSubRace(oPC));
4761 string SubraceStorage = GetSubraceStorageLocation(GetSubRace(oPC));
4762 int LetoChanges = GetSubraceDBInt(SUBRACE_DATABASE, SUBRACE_TAG + LETO_CHANGES_MADE_FOR_THIS_LEVEL + "_" + subrace, oPC);
4763
4764 if(LetoChanges >= Level)
4765 { return FALSE; }
4766
4767 int NeedsToRelog = FALSE;
4768
4769 string LetoScriptToFile = LetoSubraceModifications(oPC, SubraceStorage, Level, LetoChanges);
4770 if(LetoScriptToFile != "")
4771 {
4772 NeedsToRelog = TRUE;
4773 SetLocalString(oPC, "LETO_SCRIPT_TO_FILE", LetoScriptToFile);
4774 }
4775 SetLocalInt(oPC, "SUBRACE_NEEDS_TO_RELOG", NeedsToRelog);
4776 return NeedsToRelog;
4777}
4778
4779void SubraceOnClientLeave()
4780{
4781 object oPC = GetExitingObject();
4782 int LetoChanges = GetLocalInt(oPC, "SUBRACE_NEEDS_TO_RELOG");
4783 //Is Leto Enabled? Is there any changes to be made?
4784 //No ID check needed, since SSE do not make Leto requests for sub-raceless players.
4785 if(!ENABLE_LETO && !LetoChanges)
4786 { return; }
4787 if(LetoChanges)
4788 {
4789 int Level = GetPlayerLevel(oPC);
4790 string SubraceStorage = GetSubraceStorageLocationByID(GetPlayerSubraceID(oPC));
4791 string BicFile = LETO_GetBicPath(oPC);
4792 string ScriptForLeto = GetLocalString(oPC, "LETO_SCRIPT_TO_FILE");
4793
4794 WriteTimestampedLogEntry("*Subrace Engine LETOScript call for " + GetName(oPC) + " | " + GetLocalString(oPC, "SUBR_PlayerName") + " | " + BicFile + "* ");
4795 string LetoError = LetoScript("%char= q!"+BicFile+"!; "+ScriptForLeto+"%char = '>'; close %char; ");
4796 if(LetoError != "")
4797 {
4798 WriteTimestampedLogEntry("*Subrace Engine LETOScript Error: " + LetoError + "*");
4799 }
4800 DeleteLocalString(oPC, "LETO_SCRIPT_TO_FILE");
4801 DeleteLocalInt(oPC, "SUBRACE_NEEDS_TO_RELOG");
4802 }
4803}
4804
4805string CheckAndModifyBaseStats(object oPC, string SubraceStorage, int Level)
4806{
4807 string script = "";
4808 string SubraceStorage1 = SubraceStorage + "_" + IntToString(Level);
4809 int HasBMods = GetSSEInt( SubraceStorage1 + "_" + SUBRACE_HAS_BASE_STAT_MODIFIERS);
4810 if(HasBMods)
4811 {
4812 int StrengthModifier = GetSSEInt( SubraceStorage1 + "_" + SUBRACE_BASE_STAT_STR_MODIFIER);
4813 int DexterityModifier = GetSSEInt( SubraceStorage1 + "_" + SUBRACE_BASE_STAT_DEX_MODIFIER);
4814 int ConstitutionModifier = GetSSEInt( SubraceStorage1 + "_" + SUBRACE_BASE_STAT_CON_MODIFIER);
4815 int IntelligenceModifier = GetSSEInt( SubraceStorage1 + "_" + SUBRACE_BASE_STAT_INT_MODIFIER);
4816 int WisdomModifier = GetSSEInt( SubraceStorage1 + "_" + SUBRACE_BASE_STAT_WIS_MODIFIER);
4817 int CharismaModifier = GetSSEInt( SubraceStorage1 + "_" + SUBRACE_BASE_STAT_CHA_MODIFIER);
4818 int SpdModifier = GetSSEInt( SubraceStorage1 + "_" + SUBRACE_BASE_STAT_SPD_MODIFIER);
4819 int Set = GetSSEInt( SubraceStorage1 + "_" + SUBRACE_BASE_STAT_MODIFIERS_REPLACE);
4820 if(StrengthModifier)
4821 script += LETO_ModifyProperty("Str", StrengthModifier, Set);
4822 if(DexterityModifier)
4823 script += LETO_ModifyProperty("Dex", DexterityModifier, Set);
4824 if(ConstitutionModifier)
4825 script += LETO_ModifyProperty("Con", ConstitutionModifier, Set);
4826 if(WisdomModifier)
4827 script += LETO_ModifyProperty("Wis", WisdomModifier, Set);
4828 if(IntelligenceModifier)
4829 script += LETO_ModifyProperty("Int", IntelligenceModifier, Set);
4830 if(CharismaModifier)
4831 script += LETO_ModifyProperty("Cha", CharismaModifier, Set);
4832 script += LETO_SetMovementSpeed(SpdModifier);
4833 }
4834 return script;
4835}
4836
4837string CheckAndModifyFeats(object oPC, string SubraceStorage, int Level)
4838{
4839 string script = "";
4840 string SubraceStorage1 = SubraceStorage + "_" + IntToString(Level);
4841 int FeatCount = GetSSEInt( SubraceStorage1 + "_" + SUBRACE_BONUS_FEAT_COUNT);
4842 if(FeatCount > 0)
4843 {
4844 while(FeatCount)
4845 {
4846 int Feat = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + IntToString(FeatCount) + "_" + SUBRACE_BONUS_FEAT_FLAGS, SUBRACE_BONUS_FEAT_FLAG);
4847 int Remove = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + IntToString(FeatCount) + "_" + SUBRACE_BONUS_FEAT_FLAGS, SUBRACE_BONUS_FEAT_REMOVE_FLAG);
4848 FeatCount--;
4849 script += LETO_ModifyFeat(Feat, Remove);
4850 }
4851
4852 }
4853 return script;
4854}
4855
4856string CheckAndModifySkills(object oPC, string SubraceStorage, int Level)
4857{
4858 string script = "";
4859 string SubraceStorage1 = SubraceStorage + "_" + IntToString(Level);
4860 int SkillCount = GetSSEInt( SubraceStorage1 + "_" + SUBRACE_BONUS_SKILL_COUNT);
4861 if(SkillCount > 0)
4862 {
4863 while(SkillCount)
4864 {
4865 int Skill = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + IntToString(SkillCount) + "_" + SUBRACE_BONUS_SKILL_FLAGS, SUBRACE_BONUS_SKILL_FLAG);
4866 int Remove = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + IntToString(SkillCount) + "_" + SUBRACE_BONUS_SKILL_FLAGS, SUBRACE_BONUS_SKILL_REMOVE_FLAG);
4867 int Mod = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + IntToString(SkillCount) + "_" + SUBRACE_BONUS_SKILL_FLAGS, SUBRACE_BONUS_SKILL_MODIFIER_FLAG);
4868 SkillCount--;
4869 script += LETO_ModifySkill(Skill, Mod, Remove);
4870 }
4871
4872 }
4873 return script;
4874}
4875
4876string CheckAndModifySoundSet(object oPC, string SubraceStorage, int Level)
4877{
4878 string SubraceStorage1 = SubraceStorage + "_" + IntToString(Level);
4879 int Gender = (GetGender(oPC)==GENDER_MALE)?SUBRACE_SOUNDSET_MALE_FLAG:SUBRACE_SOUNDSET_FEMALE_FLAG;
4880
4881 int SoundSet = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + SUBRACE_SOUNDSET_FLAGS, Gender);
4882 if(SoundSet)
4883 {
4884 return LETO_SetSoundSet(SoundSet);
4885 }
4886 return "";
4887}
4888
4889void SubraceOnPlayerRespawn()
4890{
4891 object oPC = GetLastRespawnButtonPresser();
4892 ReapplySubraceAbilities(oPC);
4893 DelayCommand(2.0, ChangeSubraceFactions(oPC, GetStringLowerCase(GetSubRace(oPC))));
4894}
4895
4896void ReapplySubraceAbilities(object oPC)
4897{
4898 int ID = GetPlayerSubraceID(oPC);
4899 if(!ID)
4900 { return; }
4901 if(GetIsSSEDisabled())
4902 {
4903 SSE_MessageHandler(oPC, MESSAGE_SUBRACE_SSE_IS_SHUTDOWN);
4904 return;
4905 }
4906 DeleteLocalInt(oPC, SUBRACE_INFO_LOADED_ON_PC);
4907 DeleteLocalInt(oPC, SUBRACE_IN_SPELL_DARKNESS);
4908 string SubraceStorage = GetSubraceStorageLocationByID(ID);
4909 int IsLightSens = GetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_LIGHT_SENSITIVE, SUBRACE_BASE_INFORMATION_FLAGS);
4910 int IsUndergSens = GetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_UNDERGROUND_SENSITIVE, SUBRACE_BASE_INFORMATION_FLAGS);
4911 if(IsLightSens)
4912 {
4913 DeleteLocalInt(oPC,"SB_LGHT_DMGED");
4914 }
4915 if(IsUndergSens)
4916 {
4917 DeleteLocalInt(oPC,"SB_DARK_DMGED");
4918 }
4919 ApplyPermanentSubraceSpellResistance(ID, oPC);
4920 int HasDiffStats = GetSSEInt( SubraceStorage + "_" + SUBRACE_STAT_MODIFIERS);
4921 if(HasDiffStats > 0)
4922 {
4923 DeleteLocalInt(oPC, SUBRACE_STATS_STATUS);
4924 ClearSubraceTemporaryStats(oPC);
4925 }
4926 ClearSubraceEffects(oPC);
4927 int iTime = SHA_GetCurrentTime();
4928 DelayCommand(1.5*SSE_LOAD_FACTOR, ApplyTemporarySubraceAppearance(SubraceStorage, oPC, iTime ));
4929 DelayCommand(2.0*SSE_LOAD_FACTOR, ApplyPermanentSubraceAppearance(ID, oPC));
4930// 3.0.6.6
4931 DelayCommand(2.5*SSE_LOAD_FACTOR, ApplySubraceColors(oPC));
4932 DelayCommand(3.0*SSE_LOAD_FACTOR, ApplySubraceEyeColors(oPC));
4933
4934// 3.0.6.9
4935 DelayCommand(3.5*SSE_LOAD_FACTOR, ApplySubraceHead(oPC));
4936
4937 DelayCommand(4.0*SSE_LOAD_FACTOR, SearchAndDestroySkinsAndClaws(oPC));
4938 DelayCommand(4.5*SSE_LOAD_FACTOR, ApplySubraceEffect(oPC, SubraceStorage, iTime));
4939 DelayCommand(5.0*SSE_LOAD_FACTOR, EquipTemporarySubraceSkin(SubraceStorage, oPC, iTime));
4940 DelayCommand(6.0*SSE_LOAD_FACTOR, EquipTemporarySubraceClaw(SubraceStorage, oPC, iTime));
4941 DelayCommand(6.1*SSE_LOAD_FACTOR, SetLocalInt(oPC, SUBRACE_INFO_LOADED_ON_PC, TRUE));
4942}
4943
4944int SHA_GetCurrentTime()
4945{
4946 if(GetIsNight() || GetIsDusk())
4947 {
4948 return TIME_NIGHT;
4949 }
4950 return TIME_DAY;
4951}
4952
4953void SwapAppearance(object oPC, string subrace)
4954{
4955 string SubraceStorage = GetSubraceStorageLocation(subrace);
4956 int Level = GetPlayerLevel(oPC);
4957 while(Level)
4958 {
4959 string SubraceStorage1 = SubraceStorage + "_" + IntToString(Level);
4960 int iTime = GetLocalGroupFlagValue(oStorer, SubraceStorage1 + "_" + APPEARANCE_CHANGE, TIME_FLAGS);
4961 if(iTime)
4962 {
4963 if(SHA_GetDefaultAppearanceType(oPC) == GetAppearanceType(oPC))
4964 {
4965 ChangePCAppearance(oPC, SubraceStorage1);
4966 object oArea = GetArea(oPC);
4967 int AreaLocation = GetIsAreaAboveGround(oArea);
4968 int Interior = GetIsAreaInterior(oArea);
4969 int Natural = GetIsAreaNatural(oArea);
4970 ApplyTemporarySubraceStats(oPC, SubraceStorage, TIME_SPECIAL_APPEARANCE_SUBRACE, AreaLocation, Interior, Natural);
4971 DelayCommand(3.0, CheckIfCanUseEquipedWeapon(oPC));
4972 DelayCommand(6.0, CheckIfCanUseEquippedArmor(oPC));
4973 }
4974 else
4975 {
4976 ChangeToPCDefaultAppearance(oPC);
4977 object oArea = GetArea(oPC);
4978 int AreaLocation = GetIsAreaAboveGround(oArea);
4979 int Interior = GetIsAreaInterior(oArea);
4980 int Natural = GetIsAreaNatural(oArea);
4981 ApplyTemporarySubraceStats(oPC, SubraceStorage, TIME_SPECIAL_APPEARANCE_NORMAL, AreaLocation, Interior, Natural);
4982 DelayCommand(3.0, CheckIfCanUseEquipedWeapon(oPC));
4983 DelayCommand(6.0, CheckIfCanUseEquippedArmor(oPC));
4984 }
4985 return;
4986 }
4987 Level--;
4988 }
4989}
4990void SubraceCheckItemActivated(object oPC, string sTag)
4991{
4992 string subrace = GetStringLowerCase(GetSubRace(oPC));
4993 if(subrace == "")
4994 { return; }
4995 if(subrace == sTag)
4996 {
4997 SwapAppearance(oPC, subrace);
4998 }
4999
5000}
5001
5002void SubraceOnItemActivated()
5003{
5004 object oPC = GetItemActivator();
5005 object oItem = GetItemActivated();
5006 object oTarget = GetItemActivatedTarget();
5007 string sTag = GetStringLowerCase(GetTag(oItem));
5008
5009 //Will still recognise the old tag!
5010 if(sTag == "swand" || sTag == "_dm_subrace_wand")
5011 {
5012 //Moved all of this code into the Subrace Wand's swand_StartConversation() call (see sw_main_inc or sw_proto_inc)
5013 AssignCommand(oPC, ActionStartConversation(oPC, "swand", FALSE, FALSE));
5014 }
5015 if(GetIsSSEDisabled())
5016 {
5017 return;
5018 }
5019 int iAbility = StringToInt(sTag);
5020 if (iAbility > 0 )
5021 {
5022 SubraceAbility(oPC,iAbility,oTarget);
5023 }
5024 else
5025 if(sTag == "_potion_blood")
5026 {
5027 effect eDmg;
5028 effect eVisual = EffectVisualEffect(VFX_IMP_HARM);
5029 if(Subrace_GetIsUndead(oPC))
5030 {
5031 eDmg = EffectHeal(GetMaxHitPoints(oPC));
5032 }
5033 else
5034 {
5035 int iDmg = GetCurrentHitPoints(oPC) - d4();
5036 if(iDmg < 1)
5037 {
5038 iDmg = 1;
5039 }
5040 eDmg = EffectDamage(iDmg, DAMAGE_TYPE_NEGATIVE, DAMAGE_POWER_ENERGY);
5041 }
5042 ApplyEffectToObject(DURATION_TYPE_PERMANENT, eDmg, oPC);
5043 ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVisual, GetLocation(oPC));
5044 }
5045 else if(sTag == "dimension_door")
5046 {
5047 location lTarget = GetItemActivatedTargetLocation();
5048 if (GetAreaFromLocation(lTarget)==OBJECT_INVALID) return;
5049 AssignCommand(oPC, ClearAllActions());
5050 ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD), oPC);
5051 DelayCommand(1.0, AssignCommand(oPC, ActionJumpToLocation(lTarget)));
5052 DelayCommand(1.1, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD), oPC));
5053 }
5054// b13 changed
5055 else if(sTag == "fly_to")
5056 {
5057 if (GetIsObjectValid(oTarget)) return;
5058 object oArea = GetArea(oPC);
5059 if (SSE_LIMIT_FLIGHT_INTERIOR && GetIsAreaInterior(oArea))
5060 {
5061 SendMessageToPC(oPC,"Flight limit: interior.");
5062 return;
5063 }
5064 else if (SSE_LIMIT_FLIGHT_UNDERGROUND && (!GetIsAreaAboveGround(oArea)))
5065 {
5066 SendMessageToPC(oPC,"Flight limit: underground.");
5067 return;
5068 }
5069 else
5070 {
5071 location lTarget = GetItemActivatedTargetLocation();
5072 effect eFly = EffectDisappearAppear(lTarget);
5073 ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eFly, oPC, 4.0);
5074 }
5075 }
5076//end b13
5077 else if(sTag == "faerie_fire_blue")
5078 {
5079 float FFDuration = IntToFloat(GetHitDice(oPC)*60);
5080 effect FaerieAura = MagicalEffect(EffectVisualEffect(VFX_DUR_AURA_BLUE));
5081 effect FaerieGlow = MagicalEffect(EffectVisualEffect(VFX_DUR_LIGHT_BLUE_5));
5082 ApplyEffectToObject(DURATION_TYPE_TEMPORARY,FaerieAura,oTarget,FFDuration);
5083 ApplyEffectToObject(DURATION_TYPE_TEMPORARY,FaerieGlow,oTarget,FFDuration);
5084 }
5085 else if(sTag == "faerie_fire_green")
5086 {
5087 float FFDuration = IntToFloat(GetHitDice(oPC)*60);
5088 effect FaerieAura = MagicalEffect(EffectVisualEffect(VFX_DUR_AURA_GREEN));
5089 effect FaerieGlow = MagicalEffect(EffectVisualEffect(VFX_DUR_LIGHT_GREY_5));
5090 ApplyEffectToObject(DURATION_TYPE_TEMPORARY,FaerieAura,oTarget,FFDuration);
5091 ApplyEffectToObject(DURATION_TYPE_TEMPORARY,FaerieGlow,oTarget,FFDuration);
5092 }
5093 else if(sTag == "faerie_fire_violet")
5094 {
5095 float FFDuration = IntToFloat(GetHitDice(oPC)*60);
5096 effect FaerieAura = MagicalEffect(EffectVisualEffect(VFX_DUR_AURA_PURPLE));
5097 effect FaerieGlow = MagicalEffect(EffectVisualEffect(VFX_DUR_LIGHT_PURPLE_5));
5098 ApplyEffectToObject(DURATION_TYPE_TEMPORARY,FaerieAura,oTarget,FFDuration);
5099 ApplyEffectToObject(DURATION_TYPE_TEMPORARY,FaerieGlow,oTarget,FFDuration);
5100 }
5101 else SubraceCheckItemActivated(oPC, sTag);
5102
5103}
5104
5105//3.0.6.5
5106void CheckAndApplyDefaultSubrace(object oPC)
5107{
5108 switch (GetRacialType(oPC))
5109 {
5110 case RACIAL_TYPE_DWARF:
5111 {
5112 SetSubRace(oPC,SUBRACE_DWARF_DEFAULT);
5113 }
5114 break;
5115 case RACIAL_TYPE_ELF:
5116 {
5117 SetSubRace(oPC,SUBRACE_ELF_DEFAULT);
5118 }
5119 break;
5120 case RACIAL_TYPE_GNOME:
5121 {
5122 SetSubRace(oPC,SUBRACE_GNOME_DEFAULT);
5123 }
5124 break;
5125 case RACIAL_TYPE_HALFELF:
5126 {
5127 SetSubRace(oPC,SUBRACE_HALFELF_DEFAULT);
5128 }
5129 break;
5130 case RACIAL_TYPE_HALFLING:
5131 {
5132 SetSubRace(oPC,SUBRACE_HALFLING_DEFAULT);
5133 }
5134 break;
5135 case RACIAL_TYPE_HALFORC:
5136 {
5137 SetSubRace(oPC,SUBRACE_HALFORC_DEFAULT);
5138 }
5139 break;
5140 case RACIAL_TYPE_HUMAN:
5141 {
5142 SetSubRace(oPC,SUBRACE_HUMAN_DEFAULT);
5143 }
5144 break;
5145 }
5146}
5147
5148void SubraceOnClientEnter(object oPC = OBJECT_INVALID)
5149{
5150 if(!GetIsObjectValid(oPC))
5151 {
5152 oPC = GetEnteringObject();
5153 }
5154 if(!GetIsPC(oPC))
5155 { return; }
5156 string subrace = GetSubRace(oPC);
5157
5158//3.0.6.5
5159 if(subrace == "")
5160 {
5161 if (USE_SSE_DEFAULT_RACES)
5162 {
5163 CheckAndApplyDefaultSubrace(oPC);
5164 subrace = GetSubRace(oPC);
5165 }
5166 else
5167 {
5168 return;
5169 }
5170 }
5171 object oArea = GetArea(oPC);
5172 if(!GetIsObjectValid(oArea))
5173 {
5174 //wait for the PC to enter properly...
5175 DelayCommand(2.0*SSE_LOAD_FACTOR, SubraceOnClientEnter(oPC));
5176 return;
5177 }
5178 if(!GetSSEInt( SUBRACE_INFO_LOADED_ON_MODULE))
5179 {
5180 SSE_MessageHandler(oPC, MESSAGE_MODLOAD_NOT_COMPLETE);
5181 DelayCommand(2.0*SSE_LOAD_FACTOR, SubraceOnClientEnter(oPC));
5182 return;
5183 }
5184 DeleteLocalInt(oPC, "SUBRACE_NEEDS_TO_RELOG");
5185 int infoLoaded = GetLocalInt(oPC, SUBRACE_INFO_LOADED_ON_PC);
5186
5187 if(ENABLE_LETO && !infoLoaded)
5188 {
5189 ExportSingleCharacter(oPC);
5190 SetLocalString(oPC, "SUBR_PlayerName", GetPCPlayerName(oPC));
5191 DelayCommand(5.0*SSE_LOAD_FACTOR, SetLocalString(oPC, "SUBR_FileName", GetBicFileName(oPC)));
5192 }
5193 if(GetIsSSEDisabled())
5194 {
5195 SSE_MessageHandler(oPC, MESSAGE_SUBRACE_SSE_IS_SHUTDOWN);
5196 return;
5197 }
5198 if(GetIsSSEDisabledInArea(oArea))
5199 {
5200 SSE_MessageHandler(oPC, MESSAGE_SUBRACE_SSE_IS_SHUTDOWN_IN_AREA);
5201 SetLocalInt(oPC, "LOAD_SUBRACE", TRUE);
5202 return;
5203 }
5204 if(!infoLoaded)
5205 {
5206 DelayCommand(1.0*SSE_LOAD_FACTOR, InitiateSubraceChecking(oPC));
5207 }
5208 else if(infoLoaded && RELOAD_SUBRACE_INFORMATION_UPON_RELOGIN)
5209 {
5210 DeleteLocalInt(oPC, SUBRACE_INFO_LOADED_ON_PC);
5211 DelayCommand(1.0*SSE_LOAD_FACTOR, LoadSubraceInfoOnPC(oPC, subrace));
5212 }
5213 else
5214 {
5215 DelayCommand(1.0*SSE_LOAD_FACTOR, ReapplySubraceAbilities(oPC));
5216 }
5217}
5218
5219void SHA_SendSubraceMessageToPC(object oPC, string message, int Important = TRUE)
5220{
5221 if(MINIMALISE_SUBRACE_MESSAGES_TO_PC)
5222 {
5223 if(Important)
5224 {
5225 SendMessageToPC(oPC, SUBRACE_ENGINE + message);
5226 }
5227 }
5228 else
5229 {
5230 SendMessageToPC(oPC, SUBRACE_ENGINE + message);
5231 }
5232}
5233
5234void SSE_Message_RemoveDisplayType(int MessageType)
5235{
5236 int Display = SSE_Message_GetDisplayType();
5237 Display &= (~MessageType);
5238 SSE_Message_SetDisplayType(Display);
5239}
5240
5241void SSE_Message_SetDisplayType(int MessageType)
5242{
5243 SetSSEInt(MESSAGE_DISPLAY_CONTROL, MessageType);
5244}
5245
5246void SSE_Message_AddDisplayType(int MessageType)
5247{
5248 int Display = SSE_Message_GetDisplayType(TRUE);
5249 Display |= (~MessageType);
5250 SSE_Message_SetDisplayType(Display);
5251}
5252
5253int SSE_Message_GetDisplayType(int DoNotReturnServerDefault=FALSE)
5254{
5255 int Types = GetSSEInt(MESSAGE_DISPLAY_CONTROL);
5256 if(Types)
5257 return Types;
5258 return DoNotReturnServerDefault?FALSE:MESSAGE_TYPE_SERVER_DEFAULT;
5259}
5260
5261void SSE_MessageHandler(object Receiver, int MessageReference, string VariableText="", string VariableText2="", int MessageType = MESSAGE_TYPE_DEFAULT)
5262{
5263 //Use MessageType's Type instead of MessageReference, if MessageType is not "default"
5264 int Type = ( MessageType == MESSAGE_TYPE_DEFAULT ?
5265 MessageReference & MESSAGE_HANDLER_GET_MESSAGE_TYPE
5266 :
5267 MessageType & MESSAGE_HANDLER_GET_MESSAGE_TYPE
5268 );
5269 int Message = MessageReference & MESSAGE_HANDLER_GET_MESSAGE;
5270 //No type or no message -> nothing to do.
5271 if(!Type || !Message) return;
5272 int DisplayTypes = SSE_Message_GetDisplayType();
5273 string Text = SSE_GetStandardMessage(MessageReference, VariableText, VariableText2);
5274 //Log?
5275 if(MESSAGE_TYPE_LOG & Type)
5276 {
5277 //Log is not enough to get it sent to the player as well.
5278 Type&= (~MESSAGE_TYPE_LOG);
5279 WriteTimestampedLogEntry(Text);
5280 }
5281 //Send only if we should
5282 if( (DisplayTypes & Type) || (Type & MESSAGE_TYPE_VITAL) )
5283 {
5284 SendMessageToPC(Receiver, SUBRACE_ENGINE + Text);
5285 }
5286}
5287
5288string SSE_GetStandardMessage(int Ref, string VariableText="", string VariableText2="")
5289{
5290 string Message;
5291 switch(Ref)
5292 {
5293 case MESSAGE_SUBRACE_APPEARANCE_CHANGED:
5294 Message="Your appearance has been changed to better suit your "+ SUBRACE_WHEN_ADJECTIVE +" features.";
5295 break;
5296 case MESSAGE_SUBRACE_APPEARANCE_REVERTED:
5297 Message="Your appearance has been reverted back to your typical " + SUBRACE_WHEN_ADJECTIVE +" appearance.";
5298 break;
5299 case MESSAGE_SUBRACE_CRITERIA_FAILED:
5300 Message="Character has failed to meet the following criteria(s) required to be part of the " + SUBRACE_WHEN_NOUN+":";
5301 break;
5302 case MESSAGE_CANNOT_BE_PART_OF_PRESTIGIOUS_SUBRACE:
5303 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)!";
5304 break;
5305 case MESSAGE_FAILED_TO_MEET_PRESTIGIOUS_CLASS_RESTRICTION:
5306 Message="You have failed to meet the prestigious class restrictions!";
5307 break;
5308 case MESSAGE_SUBRACE_CRITERIA_MET:
5309 Message="You have met all the requirements for your chosen "+SUBRACE_WHEN_NOUN+"!";
5310 break;
5311 case MESSAGE_SUBRACE_CRITERIA_CLASS_FAILED:
5312 Message="You have not met the class requirements for your chosen "+SUBRACE_WHEN_NOUN+".";
5313 break;
5314 case MESSAGE_SUBRACE_CRITERIA_SPECIAL_RESTRICTION_FAILED:
5315 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";
5316 break;
5317 case MESSAGE_SUBRACE_CRITERIA_ALIGNMENT_FAILED:
5318 Message="You have not met the alignment requirements for your chosen "+SUBRACE_WHEN_NOUN+".";
5319 break;
5320 case MESSAGE_SUBRACE_CRITERIA_BASE_RACE_FAILED:
5321 Message="You are not part of the base race required in order to be part of your chosen "+SUBRACE_WHEN_NOUN+".";
5322 break;
5323 case MESSAGE_SUBRACE_UNRECOGNISED:
5324 Message="You have chosen an unrecognised " + SUBRACE_WHEN_NOUN+": " + VariableText;
5325 break;
5326 case MESSAGE_SUBRACE_CLAWS_WAIT_FOR_CLAWS_EQUIPPING:
5327 Message="Please wait... while your "+ SUBRACE_WHEN_ADJECTIVE +" claws are checked and " +VariableText+".";
5328 break;
5329 case MESSAGE_SUBRACE_CLAWS_MISSING_CREATURE_WEAPON_PROFICIENCY:
5330 Message="You do not have creature weapon proficiency... yet your "+SUBRACE_WHEN_NOUN+" wants to equip a creature claw. Inform a DM!";
5331 break;
5332 case MESSAGE_SUBRACE_CLAWS_SUCCESSFULLY_EQUIPPED:
5333 Message="Your new "+SUBRACE_WHEN_ADJECTIVE+" claws should have now been properly " + VariableText +".";
5334 break;
5335 case MESSAGE_SUBRACE_ACQUIRED_UNIQUE_ITEM:
5336 Message="You have acquired "+ ColourString(VariableText,"cä") + "; a "+SUBRACE_WHEN_ADJECTIVE +" item.";
5337 break;
5338 case MESSAGE_SUBRACE_EFFECTS_APPLIED:
5339 Message=SUBRACE_WHEN_ADJECTIVE +" effects have been appiled";
5340 break;
5341 case MESSAGE_SUBRACE_IS_MISSING_FROM_SERVER:
5342 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";
5343 break;
5344 case MESSAGE_SUBRACE_LOADING_DATA:
5345 Message="Loading your " + SUBRACE_WHEN_NOUN+ "; " + VariableText + "'s data...";
5346 break;
5347 case MESSAGE_SUBRACE_DATA_LOADED:
5348 Message="Your "+ SUBRACE_WHEN_ADJECTIVE +" data has been loaded on your character.";
5349 break;
5350 case MESSAGE_LETO_AUTOPORTAL:
5351//b13 fix
5352 Message=ColourString("Changes need to be made to your character; you are about to be teleported in: "+VariableText + " seconds.","cä");
5353 break;
5354 case MESSAGE_LETO_AUTOBOOT:
5355 Message=ColourString("You will be automatically booted in: " + VariableText + " seconds.", "cä");
5356 break;
5357 case MESSAGE_LETO_DONT_PANIC_JUSTPORTING:
5358 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ä");
5359 break;
5360 case MESSAGE_LETO_PLEASE_RELOG:
5361 Message="Changes need to be made to your character; Please re-log into the sever.";
5362 break;
5363 case MESSAGE_SUBRACE_PURGING:
5364 Message="Purging sub-race...";
5365 break;
5366 case MESSAGE_SUBRACE_PURGED:
5367 Message="Purging sub-race...DONE.";
5368 break;
5369 case MESSAGE_SUBRACE_SPELL_RESISTANCE_APPLIED:
5370 Message="Your spell resistance has been modified to fit your "+ SUBRACE_WHEN_ADJECTIVE +" features.";
5371 break;
5372 case MESSAGE_ABILITY_SCORES_REVERTED:
5373 Message="Your day/night ability scores have been reverted.";
5374 break;
5375 case MESSAGE_ABILITY_SCORES_CHANGED:
5376 Message="Your day/night ability scores have changed...";
5377 break;
5378 case MESSAGE_ABILITY_SCORES_APPEARANCE_TRIGGERED_REVERTED:
5379 Message="Your special appearance ability scores have been reverted.";
5380 break;
5381 case MESSAGE_ABILITY_SCORES_APPEARANCE_TRIGGERED_CHANGED:
5382 Message="Your special appearance scores have changed...";
5383 break;
5384 case MESSAGE_SUBRACE_CANNOT_EQUIP_ITEM:
5385 Message="You cannot equip this " +VariableText +" because of your "+SUBRACE_WHEN_NOUN+"'s limitations.";
5386 break;
5387 case MESSAGE_SUBRACE_SWITCH_CHECKING_REQUIREMENTS:
5388 Message="Checking whether your character meets the requirements for the '" + VariableText + "' "+SUBRACE_WHEN_NOUN+"...";
5389 break;
5390 case MESSAGE_SUBRACE_FAILED_REQUIREMENTS_ALIGNMENT_FOR_SWITCH:
5391 Message="Your character has failed to meet criteria for the '" + VariableText + "' " + SUBRACE_WHEN_NOUN;
5392 break;
5393 case MESSAGE_SUBRACE_SWITCHING:
5394 Message="Switching sub-races to: " + VariableText;
5395 break;
5396 case MESSAGE_SUBRACE_SWITCHED:
5397 Message="Sub-race was switched!";
5398 break;
5399 case MESSAGE_SUBRACE_FACTION_ADJUSTED:
5400 Message="Your faction has been adjusted to fit your "+SUBRACE_WHEN_NOUN+".";
5401 break;
5402 case MESSAGE_SUBRACE_MOVE_TO_START_LOCATION:
5403 Message="Welcome to " + VariableText + " " +SUBRACE_WHEN_NOUN +"'s start location.";
5404 break;
5405 case MESSAGE_SUBRACE_NEW_WINGS_GAINED:
5406 Message="You have gained new wings.";
5407 break;
5408 case MESSAGE_SUBRACE_NEW_TAIL_GAINED:
5409 Message="You have gained a new tail";
5410 break;
5411 case MESSAGE_SUBRACE_NEW_PORTRAIT_GAINED:
5412 Message="Your character portrait has changed";
5413 break;
5414 case MESSAGE_SUBRACE_SSE_IS_SHUTDOWN:
5415 Message="Subrace Engine has been switched off by a DM. Your " + SUBRACE_WHEN_NOUN + " will not function.";
5416 break;
5417 case MESSAGE_SUBRACE_SSE_IS_SHUTDOWN_IN_AREA:
5418 Message="Subrace Engine is switched off in this area.";
5419 break;
5420 case MESSAGE_SUBRACE_APPEARANCE_DATA_ERROR:
5421 Message="Appearance data error! Re-login to fix this problem.";
5422 break;
5423 case MESSAGE_SUBRACE_GENDER_FAILED:
5424 Message="You have not met the gender requirements for the chosen " + SUBRACE_WHEN_NOUN + ".";
5425 break;
5426 case MESSAGE_SUBRACE_FAILED_CRITERIA_SO_REMOVED:
5427 Message="Your " + SUBRACE_WHEN_NOUN + " has been removed because you did not meet the criteria(s).";
5428 break;
5429 case MESSAGE_SUBRACE_ALIAS_UNIFORMIZING:
5430 Message=VariableText + " is an alias for " + VariableText2 + ". Uniformizing.";
5431 break;
5432 case MESSAGE_SUBRACE_ALIAS_DIVERSITY:
5433 Message="Alias detected, using: " + VariableText + "'s properties.";
5434 break;
5435 case MESSAGE_MODLOAD_NOT_COMPLETE:
5436 Message="Waiting for Module to load subraces...";
5437 break;
5438 case MESSAGE_USER_MADE:
5439 Message=VariableText + VariableText2;
5440 break;
5441 }
5442 return Message;
5443}
5444
5445
5446int GetPlayerSubraceID(object Player)
5447{
5448 return GetSubraceID(GetSubRace(Player));
5449}
5450
5451//Subrace Default Heartbeat. (For use in default.nss)
5452//
5453//Version 2.7 Alpha: Much improved version of the heartbeat.
5454// Some of the weights of the checks and things are taken off
5455// the script by an external timer object that triggers during
5456// day night transition.
5457//
5458// Added: SubraceStorage + "_" + SUBRACE_HAS_DAY_NIGHT_EFFECTS -- an int
5459// that stores TRUE if the subrace has temporary stats or
5460// has light sensitivity, damaged by light etc (IE: Like Drow or Vampire)
5461//
5462//--- These should reduce the weight on the CPU significantly.
5463void SubraceHeartbeat(object oPC = OBJECT_SELF)
5464{
5465 if(GetLocalInt(oPC, "LOAD_SUBRACE"))
5466 {
5467 if(!GetSSEStatus(GetArea(oPC)) )
5468 {
5469 DelayCommand(1.0*SSE_LOAD_FACTOR, InitiateSubraceChecking(oPC));
5470 DeleteLocalInt(oPC, "LOAD_SUBRACE");
5471 }
5472 return;
5473 }
5474 int ID = GetPlayerSubraceID(oPC);
5475 if(!ID || !GetLocalInt(oPC, SUBRACE_INFO_LOADED_ON_PC))
5476 { return; }
5477 object oArea = GetArea(oPC);
5478 if(GetSSEStatus(oArea))
5479 {
5480 return;
5481 }
5482 string SubraceStorage = GetSubraceStorageLocationByID(ID);
5483 if(GetSSEInt( SubraceStorage + "_" + SUBRACE_HAS_DAY_NIGHT_EFFECTS))
5484 {
5485 int iTime = SHA_GetCurrentTime();
5486 int AreaLocation = GetIsAreaAboveGround(oArea);
5487 int Interior = GetIsAreaInterior(oArea);
5488 int Natural = GetIsAreaNatural(oArea);
5489 int HasDiffStats = GetSSEInt( SubraceStorage + "_" + SUBRACE_STAT_MODIFIERS);
5490 if(HasDiffStats > 0)
5491 {
5492 ApplyTemporarySubraceStats(oPC, SubraceStorage, iTime, AreaLocation, Interior, Natural);
5493 }
5494 if(iTime == TIME_DAY)
5495 {
5496 if(AreaLocation == AREA_ABOVEGROUND && !Interior)
5497 {
5498 int IsLightSens = GetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_LIGHT_SENSITIVE, SUBRACE_BASE_INFORMATION_FLAGS);
5499 int DmgTakenL = GetSSEInt( SubraceStorage + "_" + DAMAGE_AMOUNT_IN_LIGHT);
5500 if(IsLightSens)
5501 {
5502 ApplyLightSensitivity(oPC);
5503 }
5504 if(DmgTakenL)
5505 {
5506 ApplyDamageWhileInLight(oPC, DmgTakenL);
5507 }
5508 }
5509 else if(AreaLocation == AREA_UNDERGROUND)
5510 {
5511 int IsUndergSens = GetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_UNDERGROUND_SENSITIVE, SUBRACE_BASE_INFORMATION_FLAGS);
5512 int DmgTakenU = GetSSEInt( SubraceStorage + "_" + DAMAGE_AMOUNT_IN_UNDERGROUND);
5513 if(IsUndergSens)
5514 {
5515 ApplyUndergroundSensitivity(oPC);
5516 }
5517 if(DmgTakenU)
5518 {
5519 ApplyDamageWhileInDark(oPC, DmgTakenU);
5520 }
5521 }
5522 }
5523 else if(iTime == TIME_NIGHT)
5524 {
5525 if(AreaLocation == AREA_UNDERGROUND)
5526 {
5527 int IsUndergSens = GetLocalGroupFlag(oStorer, SubraceStorage + "_" + SUBRACE_BASE_INFORMATION, SUBRACE_BASE_INFORMATION_UNDERGROUND_SENSITIVE, SUBRACE_BASE_INFORMATION_FLAGS);
5528 int DmgTakenU = GetSSEInt( SubraceStorage + "_" + DAMAGE_AMOUNT_IN_UNDERGROUND);
5529 if(IsUndergSens)
5530 {
5531 ApplyUndergroundSensitivity(oPC);
5532 }
5533 if(DmgTakenU)
5534 {
5535 ApplyDamageWhileInDark(oPC, DmgTakenU);
5536 }
5537 }
5538 }
5539 }
5540}