mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-31 13:16:39 +00:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
+2
-2
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -891,7 +891,8 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
|
||||
ns->spawn.invis = (invisible || hidden) ? 1 : 0; // TODO: load this before spawning players
|
||||
ns->spawn.NPC = IsClient() ? 0 : 1;
|
||||
ns->spawn.IsMercenary = IsMerc() ? 1 : 0;
|
||||
ns->spawn.IsMercenary = (IsMerc() || no_target_hotkey) ? 1 : 0;
|
||||
|
||||
ns->spawn.petOwnerId = ownerid;
|
||||
|
||||
ns->spawn.haircolor = haircolor;
|
||||
@@ -1626,7 +1627,7 @@ void Mob::SendAppearanceEffect(uint32 parm1, uint32 parm2, uint32 parm3, uint32
|
||||
la->parm4 = parm4;
|
||||
la->parm5 = parm5;
|
||||
// Note that setting the b values to 0 will disable the related effect from the corresponding parameter.
|
||||
// Setting the a value appears to have no affect at all.
|
||||
// Setting the a value appears to have no affect at all.s
|
||||
la->value1a = 1;
|
||||
la->value1b = 1;
|
||||
la->value2a = 1;
|
||||
|
||||
+3
-2
@@ -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; }
|
||||
@@ -170,7 +170,7 @@ public:
|
||||
bool IsInvisible(Mob* other = 0) const;
|
||||
void SetInvisible(uint8 state);
|
||||
bool AttackAnimation(SkillUseTypes &skillinuse, int Hand, const ItemInst* weapon);
|
||||
|
||||
|
||||
//Song
|
||||
bool UseBardSpellLogic(uint16 spell_id = 0xffff, int slot = -1);
|
||||
bool ApplyNextBardPulse(uint16 spell_id, Mob *spell_target, uint16 slot);
|
||||
@@ -945,6 +945,7 @@ protected:
|
||||
int16 petpower;
|
||||
uint32 follow;
|
||||
uint32 follow_dist;
|
||||
bool no_target_hotkey;
|
||||
|
||||
uint8 gender;
|
||||
uint16 race;
|
||||
|
||||
@@ -224,6 +224,8 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, float x, float y, float z, float
|
||||
p_depop = false;
|
||||
loottable_id = d->loottable_id;
|
||||
|
||||
no_target_hotkey = d->no_target_hotkey;
|
||||
|
||||
primary_faction = 0;
|
||||
SetNPCFactionID(d->npc_faction_id);
|
||||
|
||||
@@ -1719,6 +1721,22 @@ bool Mob::HasNPCSpecialAtk(const char* parse) {
|
||||
void NPC::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
{
|
||||
Mob::FillSpawnStruct(ns, ForWho);
|
||||
|
||||
//Basic settings to make sure swarm pets work properly.
|
||||
if (GetSwarmOwner()) {
|
||||
Client *c = entity_list.GetClientByID(GetSwarmOwner());
|
||||
if(c) {
|
||||
SetAllowBeneficial(1); //Allow client cast swarm pets to be heal/buffed.
|
||||
//This is a hack to allow CLIENT swarm pets NOT to be targeted with F8. Warning: Will turn name 'Yellow'!
|
||||
if (RuleB(Pets, SwarmPetNotTargetableWithHotKey))
|
||||
ns->spawn.IsMercenary = 1;
|
||||
}
|
||||
//NPC cast swarm pets should still be targetable with F8.
|
||||
else
|
||||
ns->spawn.IsMercenary = 0;
|
||||
}
|
||||
|
||||
//Not recommended if using above (However, this will work better on older clients).
|
||||
if (RuleB(Pets, UnTargetableSwarmPet)) {
|
||||
if(GetOwnerID() || GetSwarmOwner()) {
|
||||
ns->spawn.is_pet = 1;
|
||||
@@ -1867,6 +1885,12 @@ void NPC::ModifyNPCStat(const char *identifier, const char *newValue)
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "PhR")
|
||||
{
|
||||
PhR = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "runspeed")
|
||||
{
|
||||
runspeed = (float)atof(val.c_str());
|
||||
|
||||
@@ -245,6 +245,7 @@ public:
|
||||
void AddLootDrop(const Item_Struct*dbitem, ItemList* itemlistconst, int16 charges, uint8 minlevel, uint8 maxlevel, bool equipit, bool wearchange = false);
|
||||
virtual void DoClassAttacks(Mob *target);
|
||||
void CheckSignal();
|
||||
inline bool IsTargetableWithHotkey() const { return no_target_hotkey; }
|
||||
|
||||
//waypoint crap
|
||||
int GetMaxWp() const { return max_wp; }
|
||||
|
||||
+6
-3
@@ -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, "$$");
|
||||
|
||||
@@ -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
|
||||
|
||||
+28
-22
@@ -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;
|
||||
|
||||
+5
-3
@@ -1099,7 +1099,8 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) {
|
||||
"npc_types.underwater,"
|
||||
"npc_types.emoteid,"
|
||||
"npc_types.spellscale,"
|
||||
"npc_types.healscale";
|
||||
"npc_types.healscale,"
|
||||
"npc_types.no_target_hotkey";
|
||||
|
||||
MakeAnyLenString(&query, "%s FROM npc_types WHERE id=%d", basic_query, id);
|
||||
|
||||
@@ -1191,7 +1192,7 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) {
|
||||
tmpNPCType->armor_tint[0] |= (atoi(row[r++]) & 0xFF) << 8;
|
||||
tmpNPCType->armor_tint[0] |= (atoi(row[r++]) & 0xFF);
|
||||
tmpNPCType->armor_tint[0] |= (tmpNPCType->armor_tint[0]) ? (0xFF << 24) : 0;
|
||||
|
||||
|
||||
int i;
|
||||
if (armor_tint_id > 0)
|
||||
{
|
||||
@@ -1281,7 +1282,8 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) {
|
||||
tmpNPCType->emoteid = atoi(row[r++]);
|
||||
tmpNPCType->spellscale = atoi(row[r++]);
|
||||
tmpNPCType->healscale = atoi(row[r++]);
|
||||
|
||||
tmpNPCType->no_target_hotkey = atoi(row[r++]) == 1 ? true : false;
|
||||
|
||||
// If NPC with duplicate NPC id already in table,
|
||||
// free item we attempted to add.
|
||||
if (zone->npctable.find(tmpNPCType->npc_id) != zone->npctable.end())
|
||||
|
||||
@@ -120,6 +120,7 @@ struct NPCType
|
||||
uint32 emoteid;
|
||||
float spellscale;
|
||||
float healscale;
|
||||
bool no_target_hotkey;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user