From 35cd98c7a763f62d22fa7d0e2f9029ef3a168e1a Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Wed, 9 Apr 2014 05:17:36 -0400 Subject: [PATCH] -Implemented the ability to properly use live spell projectile graphics. This data is found in the player_1 field of the spells_new table. -Rule for this set to be disabled by default. -Enable IF your server uses an UF+ spell file and your players use UF+ clients -Otherwise your better off with alternative method/rules already implemented so that all players can see the effect. -Added ability for PERL ProjectileAnim function to only need an IT#### and not an actual item id. -If you want it in LUA somebody needs to add it. - Change to wizard innate critical ratios based on parse data. --- changelog.txt | 12 ++++- common/ruletypes.h | 1 + .../2014_04_03_SpellProjectileRules.sql | 4 +- .../2014_04_09_SpellProjectileRule.sql | 7 +++ zone/effects.cpp | 4 +- zone/mob.h | 2 +- zone/perl_mob.cpp | 9 ++-- zone/special_attacks.cpp | 9 ++-- zone/spell_effects.cpp | 50 +++++++++++-------- 9 files changed, 64 insertions(+), 34 deletions(-) create mode 100644 utils/sql/git/optional/2014_04_09_SpellProjectileRule.sql diff --git a/changelog.txt b/changelog.txt index dafc65268..08f8df3c4 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,10 +1,20 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 04/09/2014 == +Kayen: Implemented ability to use the actual live spell projectile graphics that are defined in the modern spell file. + *This is disabled by default. Recommend enabling if your server uses an UF+ spell file AND most of your players use UF+ clients. +Kayen: Expanded the PERL ProjectileAnim(mob, item_id, [IsArrow?, speed, angle, tilt, arc, IDFile]) so you can now just set the weapon model graphic IT#### +Example: ProjectileAnim($npc, 0, 0, 1, 0, 0, 0, "IT10747") This will shoot an SK 2.0 sword. +Kayen: Updated wizard innate critical damage modifier to be from 20-70% of base damage (based on live parses) + + +Optional SQL: utils/sql/git/optional/2014_04_09_SpellProjectileRule.sql +Note: This sql also contains a query to check if your spell file is compatible. + == 04/06/2014 == Uleat: Changed Mob::CanThisClassDualWield() behavior. This should let non-monk/beastlord dual-wielding classes attack with either fist as long as the other hand is occupied. Notes: See this thread for more information and to provide feedback: http://www.eqemulator.org/forums/showthread.php?p=229328#post229328 - == 04/05/2014 == Akkadius: Fix for the Fix for the Fix: Rule Combat:OneProcPerWeapon was created so that you can revert to the original proc functionality diff --git a/common/ruletypes.h b/common/ruletypes.h index dec5a6a8f..5612a90c0 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -307,6 +307,7 @@ RULE_INT ( Spells, SuccorFailChance, 2) //Determines chance for a succor spell n RULE_INT ( Spells, FRProjectileItem_Titanium, 1113) // Item id for Titanium clients for Fire 'spell projectile'. RULE_INT ( Spells, FRProjectileItem_SOF, 80684) // Item id for SOF clients for Fire 'spell projectile'. RULE_INT ( Spells, FRProjectileItem_NPC, 80684) // Item id for NPC Fire 'spell projectile'. +RULE_BOOL ( Spells, UseLiveSpellProjectileGFX, false) // Use spell projectile graphics set in the spells_new table (player_1). Server must be using UF+ spell file. RULE_CATEGORY_END() RULE_CATEGORY( Combat ) diff --git a/utils/sql/git/optional/2014_04_03_SpellProjectileRules.sql b/utils/sql/git/optional/2014_04_03_SpellProjectileRules.sql index 3601a5fef..01950cc1a 100644 --- a/utils/sql/git/optional/2014_04_03_SpellProjectileRules.sql +++ b/utils/sql/git/optional/2014_04_03_SpellProjectileRules.sql @@ -1,3 +1,3 @@ INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Spells:FRProjectileItem_Titanium', '1113', 'Item id for Titanium clients for Fire spell projectile.'); -INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Spells:FRProjectileItem_SOF', '80684', 'Item id for Titanium clients for Fire spell projectile.'); -INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Spells:FRProjectileItem_NPC', '80684', 'Item id for Titanium clients for Fire spell projectile.'); +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Spells:FRProjectileItem_SOF', '80684', 'Item id for SOF clients for Fire spell projectile.'); +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Spells:FRProjectileItem_NPC', '80684', 'Item id for NPC to use for Fire spell projectile.'); diff --git a/utils/sql/git/optional/2014_04_09_SpellProjectileRule.sql b/utils/sql/git/optional/2014_04_09_SpellProjectileRule.sql new file mode 100644 index 000000000..1a4c9352e --- /dev/null +++ b/utils/sql/git/optional/2014_04_09_SpellProjectileRule.sql @@ -0,0 +1,7 @@ +-- Recommend enabling if your server uses an UF+ spell file and your players use UF+ client. This will give the proper graphics for all spell projectiles. +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Spells:UseLiveSpellProjectileGFX', false, ' Use spell projectile graphics set in the spells_new table (player_1). Server must be using UF+ spell file.'); + +-- Use this query to check if your spell file is compatible +-- If it returns in the player_1 field IT##### it will work. +SELECT id,name,player_1 from spells_new WHERE targettype = 1; + diff --git a/zone/effects.cpp b/zone/effects.cpp index 48e30639c..329c69084 100644 --- a/zone/effects.cpp +++ b/zone/effects.cpp @@ -79,7 +79,7 @@ int32 Client::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { if (spell_id == SPELL_IMP_HARM_TOUCH) //Improved Harm Touch value -= GetAA(aaUnholyTouch) * 450; //Unholy Touch - int chance = RuleI(Spells, BaseCritChance); + int chance = RuleI(Spells, BaseCritChance); //Wizard base critical chance is 2% (Does not scale with level) chance += itembonuses.CriticalSpellChance + spellbonuses.CriticalSpellChance + aabonuses.CriticalSpellChance; chance += itembonuses.FrenziedDevastation + spellbonuses.FrenziedDevastation + aabonuses.FrenziedDevastation; @@ -99,7 +99,7 @@ int32 Client::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { } else if (GetClass() == WIZARD && (GetLevel() >= RuleI(Spells, WizCritLevel)) && (MakeRandomInt(1,100) <= RuleI(Spells, WizCritChance))) { - ratio += MakeRandomInt(1,100); //Wizard innate critical chance is calculated seperately from spell effect and is not a set ratio. + ratio += MakeRandomInt(20,70); //Wizard innate critical chance is calculated seperately from spell effect and is not a set ratio. (20-70 is parse confirmed) Critical = true; } diff --git a/zone/mob.h b/zone/mob.h index 4ee5da5a8..a5ce86903 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -161,7 +161,7 @@ public: virtual void WearChange(uint8 material_slot, uint16 texture, uint32 color); void DoAnim(const int animnum, int type=0, bool ackreq = true, eqFilterType filter = FilterNone); void ProjectileAnimation(Mob* to, int item_id, bool IsArrow = false, float speed = 0, - float angle = 0, float tilt = 0, float arc = 0); + float angle = 0, float tilt = 0, float arc = 0, const char *IDFile = nullptr); void ChangeSize(float in_size, bool bNoRestriction = false); inline uint8 SeeInvisible() const { return see_invis; } inline bool SeeInvisibleUndead() const { return see_invis_undead; } diff --git a/zone/perl_mob.cpp b/zone/perl_mob.cpp index a2958db27..86cf58981 100644 --- a/zone/perl_mob.cpp +++ b/zone/perl_mob.cpp @@ -6856,7 +6856,7 @@ XS(XS_Mob_ProjectileAnim); /* prototype to pass -Wmissing-prototypes */ XS(XS_Mob_ProjectileAnim) { dXSARGS; - if (items < 3 || items > 8) + if (items < 3 || items > 9) Perl_croak(aTHX_ "Usage: Mob::ProjectileAnim(THIS, mob, item_id, IsArrow?, speed, angle, tilt, arc)"); { @@ -6868,6 +6868,7 @@ XS(XS_Mob_ProjectileAnim) float angle = 0; float tilt = 0; float arc = 0; + char * IDFile = nullptr; if (sv_derived_from(ST(0), "Mob")) { IV tmp = SvIV((SV*)SvRV(ST(0))); @@ -6903,7 +6904,9 @@ XS(XS_Mob_ProjectileAnim) arc = (float)SvNV(ST(7)); } - THIS->ProjectileAnimation(mob, item_id, IsArrow, speed, angle, tilt, arc); + if (items > 8) { IDFile = (char *)SvPV_nolen(ST(8)); } + + THIS->ProjectileAnimation(mob, item_id, IsArrow, speed, angle, tilt, arc, IDFile); } XSRETURN_EMPTY; @@ -8389,7 +8392,7 @@ XS(boot_Mob) newXSproto(strcpy(buf, "CheckLoS"), XS_Mob_CheckLoS, file, "$$"); newXSproto(strcpy(buf, "CheckLoSToLoc"), XS_Mob_CheckLoSToLoc, file, "$$$$;$"); newXSproto(strcpy(buf, "FindGroundZ"), XS_Mob_FindGroundZ, file, "$$$;$"); - newXSproto(strcpy(buf, "ProjectileAnim"), XS_Mob_ProjectileAnim, file, "$$$;$$$$$"); + newXSproto(strcpy(buf, "ProjectileAnim"), XS_Mob_ProjectileAnim, file, "$$$;$$$$$$"); newXSproto(strcpy(buf, "HasNPCSpecialAtk"), XS_Mob_HasNPCSpecialAtk, file, "$$"); newXSproto(strcpy(buf, "SendAppearanceEffect"), XS_Mob_SendAppearanceEffect, file, "$$;$$$$"); newXSproto(strcpy(buf, "SetFlyMode"), XS_Mob_SetFlyMode, file, "$$"); diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index 8d95524fe..54e70f3d0 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -1346,7 +1346,7 @@ void Mob::SendItemAnimation(Mob *to, const Item_Struct *item, SkillUseTypes skil safe_delete(outapp); } -void Mob::ProjectileAnimation(Mob* to, int item_id, bool IsArrow, float speed, float angle, float tilt, float arc) { +void Mob::ProjectileAnimation(Mob* to, int item_id, bool IsArrow, float speed, float angle, float tilt, float arc, const char *IDFile) { const Item_Struct* item = nullptr; uint8 item_type = 0; @@ -1380,6 +1380,10 @@ void Mob::ProjectileAnimation(Mob* to, int item_id, bool IsArrow, float speed, f arc = 50; } + const char *item_IDFile = item->IDFile; + + if (IDFile && (strncmp(IDFile, "IT", 2) == 0)) + item_IDFile = IDFile; // See SendItemAnimation() for some notes on this struct EQApplicationPacket *outapp = new EQApplicationPacket(OP_SomeItemPacketMaybe, sizeof(Arrow_Struct)); @@ -1393,7 +1397,7 @@ void Mob::ProjectileAnimation(Mob* to, int item_id, bool IsArrow, float speed, f as->item_id = item->ID; as->item_type = item_type; as->skill = 0; // Doesn't seem to have any effect - strn0cpy(as->model_name, item->IDFile, 16); + strn0cpy(as->model_name, item_IDFile, 16); as->velocity = speed; as->launch_angle = angle; as->tilt = tilt; @@ -1406,7 +1410,6 @@ void Mob::ProjectileAnimation(Mob* to, int item_id, bool IsArrow, float speed, f } - void NPC::DoClassAttacks(Mob *target) { if(target == nullptr) return; //gotta have a target for all these diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index ce299ed36..ad7e273fd 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -3351,10 +3351,7 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste case SE_Root: { /* Root formula derived from extensive personal live parses - Kayen - ROOT has a 40% chance to do a resist check to break. - Resist check has NO LOWER bounds. - If multiple roots on target. Root in first slot will be checked first to break from nukes. - If multiple roots on target and broken by spell. Roots are removed ONE at a time in order of buff slot. + ROOT has a 70% chance to do a resist check to break. */ if (MakeRandomInt(0, 99) < RuleI(Spells, RootBreakCheckChance)){ @@ -6064,26 +6061,35 @@ bool Mob::TrySpellProjectile(Mob* spell_target, uint16 spell_id){ projectile_timer.Start(250); } - //Only use fire graphic for fire spells. - if (spells[spell_id].resisttype == RESIST_FIRE) { - - if (IsClient()){ - if (CastToClient()->GetClientVersionBit() <= 4) //Titanium needs alternate graphic. - ProjectileAnimation(spell_target,(RuleI(Spells, FRProjectileItem_Titanium)), false, 1.5); - else - ProjectileAnimation(spell_target,(RuleI(Spells, FRProjectileItem_SOF)), false, 1.5); - } - - else - ProjectileAnimation(spell_target,(RuleI(Spells, FRProjectileItem_NPC)), false, 1.5); - - if (spells[spell_id].CastingAnim == 64) - anim = 44; //Corrects for animation error. + //This will use the correct graphic as defined in the player_1 field of spells_new table. Found in UF+ spell files. + if (RuleB(Spells, UseLiveSpellProjectileGFX)) { + ProjectileAnimation(spell_target,0, false, 1.5,0,0,0, spells[spell_id].player_1); } - //Pending other types of projectile graphics. (They will function but with a default arrow graphic for now) - else - ProjectileAnimation(spell_target,0, 1, 1.5); + //This allows limited support for server using older spell files that do not contain data for bolt graphics. + else { + //Only use fire graphic for fire spells. + if (spells[spell_id].resisttype == RESIST_FIRE) { + + if (IsClient()){ + if (CastToClient()->GetClientVersionBit() <= 4) //Titanium needs alternate graphic. + ProjectileAnimation(spell_target,(RuleI(Spells, FRProjectileItem_Titanium)), false, 1.5); + else + ProjectileAnimation(spell_target,(RuleI(Spells, FRProjectileItem_SOF)), false, 1.5); + } + + else + ProjectileAnimation(spell_target,(RuleI(Spells, FRProjectileItem_NPC)), false, 1.5); + + } + + //Default to an arrow if not using a mage bolt (Use up to date spell file and enable above rules for best results) + else + ProjectileAnimation(spell_target,0, 1, 1.5); + } + + if (spells[spell_id].CastingAnim == 64) + anim = 44; //Corrects for animation error. DoAnim(anim, 0, true, IsClient() ? FilterPCSpells : FilterNPCSpells); //Override the default projectile animation. return true;