Spirit Shards, Group and Solo EXP Debt (PVE/PVP), new lua functions, rules included
xp_debt in InfoStruct changed to float use SetInfoStructFloat and GetInfoStructFloat for it SpawnScript file is now listed in /spawn details on the last page LUA functions added: bool GetRuleFlagBool(category, name) float GetRuleFlagFloat(category, name) int32 GetShardID(Spawn) int32 GetShardCharID(Spawn) int64 GetShardCreatedTimestamp(Spawn) bool DeleteDBShardID(shardid) -- using GetShardID int32 GetCharacterID(Spawn) bool SetAccessToEntityCommandByCharID(Spawn, CharID, command_string, val) -- same as SetAccessToEntityCommand, but using a CharID instead of player Rules added: RULE_INIT(R_Combat, DeathExperienceDebt, "50.00"); // divide by 100, 50/100 = .5% debt per pve death RULE_INIT(R_Combat, PVPDeathExperienceDebt, "25.00"); // divide by 100, 25/100 = .25% debt per pvp death RULE_INIT(R_Combat, GroupExperienceDebt, "0"); // set to 1 means we will share debt between the group RULE_INIT(R_Combat, ExperienceToDebt, "50.00"); // percentage of xp earned to debt vs obtained xp 50/100 = 50% to debt RULE_INIT(R_Combat, ExperienceDebtRecoveryPercent, "5.00"); // recovery percentage per period of time, 5/100 = 5% recovered (so if .5% debt, .5*.05 = .025, .5-.025=.475% debt left) RULE_INIT(R_Combat, ExperienceDebtRecoveryPeriod, "600"); // every 10 minutes (x*60 seconds) recover ExperienceDebtRecoveryPercent RULE_INIT(R_Combat, EnableSpiritShards, "1"); RULE_INIT(R_Combat, SpiritShardSpawnScript, "SpawnScripts/Generic/SpiritShard.lua"); RULE_INIT(R_Combat, ShardDebtRecoveryPercent, "25.00"); // recovered percentage of debt upon obtainig shard, 25/100 means 25%. If there is .5 DeathExperienceDebt, .5*25% = .125, .5 - .125 = .375
This commit is contained in:
parent
ce323835bf
commit
65e7222de5
21 changed files with 715 additions and 29 deletions
41
DB/updates/spiritshards_xpdebt_feb7_2021.sql
Normal file
41
DB/updates/spiritshards_xpdebt_feb7_2021.sql
Normal file
|
@ -0,0 +1,41 @@
|
|||
alter table character_details modify column xp_debt float not null default 0.0;
|
||||
CREATE TABLE `character_spirit_shards` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`timestamp` BIGINT signed NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`name` varchar(64) not null default '',
|
||||
`level` int(10) unsigned NOT NULL DEFAULT 0,
|
||||
`race` tinyint(3) unsigned NOT NULL DEFAULT 0,
|
||||
`gender` tinyint(3) unsigned NOT NULL DEFAULT 0,
|
||||
`adventure_class` tinyint(3) unsigned NOT NULL DEFAULT 0,
|
||||
`model_type` mediumint(8) unsigned NOT NULL DEFAULT 0,
|
||||
`soga_model_type` mediumint(8) unsigned NOT NULL DEFAULT 0,
|
||||
`hair_type` mediumint(8) unsigned NOT NULL DEFAULT 0,
|
||||
`hair_face_type` mediumint(8) unsigned NOT NULL DEFAULT 0,
|
||||
`wing_type` mediumint(8) unsigned NOT NULL DEFAULT 0,
|
||||
`chest_type` mediumint(8) unsigned NOT NULL DEFAULT 0,
|
||||
`legs_type` mediumint(8) unsigned NOT NULL DEFAULT 0,
|
||||
`soga_hair_type` mediumint(8) unsigned NOT NULL DEFAULT 0,
|
||||
`soga_hair_face_type` mediumint(8) unsigned NOT NULL DEFAULT 0,
|
||||
`hide_hood` tinyint(3) unsigned NOT NULL DEFAULT 0,
|
||||
`size` mediumint(8) unsigned NOT NULL DEFAULT 0,
|
||||
`collision_radius` mediumint(8) unsigned NOT NULL DEFAULT 0,
|
||||
`action_state` mediumint(8) unsigned NOT NULL DEFAULT 0,
|
||||
`visual_state` mediumint(8) unsigned NOT NULL DEFAULT 0,
|
||||
`mood_state` mediumint(8) unsigned NOT NULL DEFAULT 0,
|
||||
`emote_state` mediumint(8) unsigned NOT NULL DEFAULT 0,
|
||||
`pos_state` mediumint(8) unsigned NOT NULL DEFAULT 0,
|
||||
`activity_status` mediumint(8) unsigned NOT NULL DEFAULT 0,
|
||||
`sub_title` varchar(255) not null default '',
|
||||
`prefix_title` varchar(128) not null default '',
|
||||
`suffix_title` varchar(128) not null default '',
|
||||
`lastname` varchar(64) not null default '',
|
||||
`x` float not null default 0.0,
|
||||
`y` float not null default 0.0,
|
||||
`z` float not null default 0.0,
|
||||
`heading` float not null default 0.0,
|
||||
`gridid` int(10) unsigned NOT NULL DEFAULT 0,
|
||||
`zoneid` int(10) unsigned NOT NULL DEFAULT 0,
|
||||
`instanceid` int(10) unsigned NOT NULL DEFAULT 0,
|
||||
`charid` int(10) unsigned NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
|
@ -30,6 +30,7 @@
|
|||
#include "LuaInterface.h"
|
||||
#include "Rules/Rules.h"
|
||||
#include "SpellProcess.h"
|
||||
#include "World.h"
|
||||
#include <math.h>
|
||||
|
||||
extern Classes classes;
|
||||
|
@ -37,6 +38,7 @@ extern ConfigReader configReader;
|
|||
extern MasterSkillList master_skill_list;
|
||||
extern RuleManager rule_manager;
|
||||
extern LuaInterface* lua_interface;
|
||||
extern World world;
|
||||
|
||||
/* ******************************************************************************
|
||||
|
||||
|
@ -1183,6 +1185,51 @@ void Entity::KillSpawn(Spawn* dead, int8 damage_type, int16 kill_blow_type) {
|
|||
GetZone()->KillSpawn(true, dead, this, true, damage_type, kill_blow_type);
|
||||
}
|
||||
|
||||
void Entity::HandleDeathExperienceDebt(Spawn* killer)
|
||||
{
|
||||
if(!IsPlayer())
|
||||
return;
|
||||
|
||||
float ruleDebt = 0.0f;
|
||||
|
||||
if(killer && killer->IsPlayer())
|
||||
ruleDebt = rule_manager.GetGlobalRule(R_Combat, PVPDeathExperienceDebt)->GetFloat()/100.0f;
|
||||
else
|
||||
ruleDebt = rule_manager.GetGlobalRule(R_Combat, DeathExperienceDebt)->GetFloat()/100.0f;
|
||||
|
||||
if(ruleDebt > 0.0f)
|
||||
{
|
||||
bool groupDebt = rule_manager.GetGlobalRule(R_Combat, GroupExperienceDebt)->GetBool();
|
||||
if(groupDebt && ((Player*)this)->GetGroupMemberInfo())
|
||||
{
|
||||
world.GetGroupManager()->GroupLock(__FUNCTION__, __LINE__);
|
||||
PlayerGroup* group = world.GetGroupManager()->GetGroup(((Player*)this)->GetGroupMemberInfo()->group_id);
|
||||
if (group)
|
||||
{
|
||||
group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
|
||||
deque<GroupMemberInfo*>* members = group->GetMembers();
|
||||
int32 size = members->size();
|
||||
float xpDebtPerMember = ruleDebt/(float)size;
|
||||
deque<GroupMemberInfo*>::iterator itr;
|
||||
for (itr = members->begin(); itr != members->end(); itr++) {
|
||||
GroupMemberInfo* gmi = *itr;
|
||||
if (gmi->client && gmi->client->GetPlayer()) {
|
||||
gmi->client->GetPlayer()->GetInfoStruct()->set_xp_debt(gmi->client->GetPlayer()->GetInfoStruct()->get_xp_debt()+xpDebtPerMember);
|
||||
gmi->client->GetPlayer()->SetCharSheetChanged(true);
|
||||
}
|
||||
}
|
||||
group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
|
||||
}
|
||||
world.GetGroupManager()->ReleaseGroupLock(__FUNCTION__, __LINE__);
|
||||
}
|
||||
else
|
||||
{
|
||||
((Player*)this)->GetInfoStruct()->set_xp_debt(((Player*)this)->GetInfoStruct()->get_xp_debt()+ruleDebt);
|
||||
((Player*)this)->SetCharSheetChanged(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Entity::ProcessCombat() {
|
||||
// This is a virtual function so when a NPC calls this it will use the NPC::ProcessCombat() version
|
||||
// and a player will use the Player::ProcessCombat() version, leave this function blank.
|
||||
|
|
|
@ -3830,6 +3830,10 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
|
|||
if (spawn->IsNPC()) {
|
||||
details4 += "\nRandomize: " + to_string(((NPC*)spawn)->GetRandomize()) + "\n";
|
||||
}
|
||||
|
||||
const char* spawnScriptMsg = (spawn->GetSpawnScript() && strlen(spawn->GetSpawnScript())>0) ? spawn->GetSpawnScript() : "Not Set";
|
||||
|
||||
details4 += "\nSpawnScript: " + std::string(spawnScriptMsg) + "\n";
|
||||
}
|
||||
|
||||
string title = string(spawn->GetName()) + "(" + to_string(spawn->GetDatabaseID()) + ")";
|
||||
|
|
|
@ -178,7 +178,7 @@ void Entity::MapInfoStruct()
|
|||
get_int16_funcs["absorb"] = l::bind(&InfoStruct::get_absorb, &info_struct);
|
||||
get_int32_funcs["xp"] = l::bind(&InfoStruct::get_xp, &info_struct);
|
||||
get_int32_funcs["xp_needed"] = l::bind(&InfoStruct::get_xp_needed, &info_struct);
|
||||
get_int32_funcs["xp_debt"] = l::bind(&InfoStruct::get_xp_debt, &info_struct);
|
||||
get_float_funcs["xp_debt"] = l::bind(&InfoStruct::get_xp_debt, &info_struct);
|
||||
get_int16_funcs["xp_yellow"] = l::bind(&InfoStruct::get_xp_yellow, &info_struct);
|
||||
get_int16_funcs["xp_yellow_vitality_bar"] = l::bind(&InfoStruct::get_xp_yellow_vitality_bar, &info_struct);
|
||||
get_int16_funcs["xp_blue_vitality_bar"] = l::bind(&InfoStruct::get_xp_blue_vitality_bar, &info_struct);
|
||||
|
@ -318,7 +318,7 @@ void Entity::MapInfoStruct()
|
|||
set_int16_funcs["absorb"] = l::bind(&InfoStruct::set_absorb, &info_struct, l::_1);
|
||||
set_int32_funcs["xp"] = l::bind(&InfoStruct::set_xp, &info_struct, l::_1);
|
||||
set_int32_funcs["xp_needed"] = l::bind(&InfoStruct::set_xp_needed, &info_struct, l::_1);
|
||||
set_int32_funcs["xp_debt"] = l::bind(&InfoStruct::set_xp_debt, &info_struct, l::_1);
|
||||
set_float_funcs["xp_debt"] = l::bind(&InfoStruct::set_xp_debt, &info_struct, l::_1);
|
||||
set_int16_funcs["xp_yellow"] = l::bind(&InfoStruct::set_xp_yellow, &info_struct, l::_1);
|
||||
set_int16_funcs["xp_yellow_vitality_bar"] = l::bind(&InfoStruct::set_xp_yellow_vitality_bar, &info_struct, l::_1);
|
||||
set_int16_funcs["xp_blue_vitality_bar"] = l::bind(&InfoStruct::set_xp_blue_vitality_bar, &info_struct, l::_1);
|
||||
|
|
|
@ -191,7 +191,7 @@ struct InfoStruct{
|
|||
absorb_ = 0;
|
||||
xp_ = 0;
|
||||
xp_needed_ = 0;
|
||||
xp_debt_ = 0;
|
||||
xp_debt_ = 0.0f;
|
||||
xp_yellow_ = 0;
|
||||
xp_yellow_vitality_bar_ = 0;
|
||||
xp_blue_vitality_bar_ = 0;
|
||||
|
@ -489,7 +489,7 @@ struct InfoStruct{
|
|||
int16 get_absorb() { std::lock_guard<std::mutex> lk(classMutex); return absorb_; }
|
||||
int32 get_xp() { std::lock_guard<std::mutex> lk(classMutex); return xp_; }
|
||||
int32 get_xp_needed() { std::lock_guard<std::mutex> lk(classMutex); return xp_needed_; }
|
||||
int32 get_xp_debt() { std::lock_guard<std::mutex> lk(classMutex); return xp_debt_; }
|
||||
float get_xp_debt() { std::lock_guard<std::mutex> lk(classMutex); return xp_debt_; }
|
||||
int16 get_xp_yellow() { std::lock_guard<std::mutex> lk(classMutex); return xp_yellow_; }
|
||||
int16 get_xp_yellow_vitality_bar() { std::lock_guard<std::mutex> lk(classMutex); return xp_yellow_vitality_bar_; }
|
||||
int16 get_xp_blue_vitality_bar() { std::lock_guard<std::mutex> lk(classMutex); return xp_blue_vitality_bar_; }
|
||||
|
@ -658,7 +658,7 @@ struct InfoStruct{
|
|||
void set_xp(int32 value) { std::lock_guard<std::mutex> lk(classMutex); xp_ = value; }
|
||||
void set_xp_needed(int32 value) { std::lock_guard<std::mutex> lk(classMutex); xp_needed_ = value; }
|
||||
|
||||
void set_xp_debt(int32 value) { std::lock_guard<std::mutex> lk(classMutex); xp_debt_ = value; }
|
||||
void set_xp_debt(float value) { std::lock_guard<std::mutex> lk(classMutex); xp_debt_ = value; }
|
||||
|
||||
void set_xp_yellow(int16 value) { std::lock_guard<std::mutex> lk(classMutex); xp_yellow_ = value; }
|
||||
void set_xp_blue(int16 value) { std::lock_guard<std::mutex> lk(classMutex); xp_blue_ = value; }
|
||||
|
@ -891,7 +891,7 @@ private:
|
|||
int16 absorb_;
|
||||
int32 xp_;
|
||||
int32 xp_needed_;
|
||||
int32 xp_debt_;
|
||||
float xp_debt_;
|
||||
int16 xp_yellow_;
|
||||
int16 xp_yellow_vitality_bar_;
|
||||
int16 xp_blue_vitality_bar_;
|
||||
|
@ -1194,6 +1194,7 @@ public:
|
|||
void AddHate(Entity* attacker, sint32 hate);
|
||||
bool CheckInterruptSpell(Entity* attacker);
|
||||
void KillSpawn(Spawn* dead, int8 damage_type = 0, int16 kill_blow_type = 0);
|
||||
void HandleDeathExperienceDebt(Spawn* killer);
|
||||
void SetAttackDelay(bool primary = false, bool ranged = false);
|
||||
float CalculateAttackSpeedMod();
|
||||
virtual void ProcessCombat();
|
||||
|
|
|
@ -1007,6 +1007,19 @@ int EQ2Emu_lua_IsPlayer(lua_State* state) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int EQ2Emu_lua_GetCharacterID(lua_State* state) {
|
||||
if (!lua_interface)
|
||||
return 0;
|
||||
Spawn* spawn = lua_interface->GetSpawn(state);
|
||||
if (spawn && spawn->IsPlayer()) {
|
||||
lua_interface->SetInt32Value(state, ((Player*)spawn)->GetCharacterID());
|
||||
return 1;
|
||||
}
|
||||
|
||||
lua_interface->SetInt32Value(state, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EQ2Emu_lua_FaceTarget(lua_State* state) {
|
||||
if (!lua_interface)
|
||||
return 0;
|
||||
|
@ -10667,6 +10680,7 @@ int EQ2Emu_lua_SetAccessToEntityCommand(lua_State* state)
|
|||
string command = lua_interface->GetStringValue(state, 3);
|
||||
bool val = (lua_interface->GetInt8Value(state, 4) == 1);
|
||||
|
||||
lua_interface->ResetFunctionStack(state);
|
||||
if (spawn && player && player->IsPlayer())
|
||||
{
|
||||
EntityCommand* cmd = spawn->FindEntityCommand(string(command), true);
|
||||
|
@ -10681,6 +10695,32 @@ int EQ2Emu_lua_SetAccessToEntityCommand(lua_State* state)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int EQ2Emu_lua_SetAccessToEntityCommandByCharID(lua_State* state)
|
||||
{
|
||||
if (!lua_interface)
|
||||
return 0;
|
||||
|
||||
Spawn* spawn = lua_interface->GetSpawn(state);
|
||||
int32 charID = lua_interface->GetInt32Value(state, 2);
|
||||
string command = lua_interface->GetStringValue(state, 3);
|
||||
bool val = (lua_interface->GetInt8Value(state, 4) == 1);
|
||||
|
||||
lua_interface->ResetFunctionStack(state);
|
||||
if (spawn && charID)
|
||||
{
|
||||
EntityCommand* cmd = spawn->FindEntityCommand(string(command), true);
|
||||
bool res = false;
|
||||
if (cmd)
|
||||
res = spawn->SetPermissionToEntityCommandByCharID(cmd, charID, val);
|
||||
|
||||
lua_interface->SetBooleanValue(state, res);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EQ2Emu_lua_RemovePrimaryEntityCommand(lua_State* state)
|
||||
{
|
||||
if (!lua_interface)
|
||||
|
@ -10689,6 +10729,7 @@ int EQ2Emu_lua_RemovePrimaryEntityCommand(lua_State* state)
|
|||
Spawn* spawn = lua_interface->GetSpawn(state);
|
||||
string command = lua_interface->GetStringValue(state, 2);
|
||||
|
||||
lua_interface->ResetFunctionStack(state);
|
||||
if (spawn && command.length() > 0)
|
||||
spawn->RemovePrimaryEntityCommand(command.c_str());
|
||||
|
||||
|
@ -10705,6 +10746,7 @@ int EQ2Emu_lua_SendUpdateDefaultCommand(lua_State* state) {
|
|||
string command = lua_interface->GetStringValue(state, 3);
|
||||
Spawn* player = lua_interface->GetSpawn(state, 4);
|
||||
|
||||
lua_interface->ResetFunctionStack(state);
|
||||
if (spawn) {
|
||||
spawn->GetZone()->SendUpdateDefaultCommand(spawn, command.c_str(), distance, player);
|
||||
}
|
||||
|
@ -10719,6 +10761,7 @@ int EQ2Emu_lua_SendTransporters(lua_State* state) {
|
|||
Spawn* player = lua_interface->GetSpawn(state, 2);
|
||||
int32 transport_id = lua_interface->GetInt32Value(state, 3);
|
||||
|
||||
lua_interface->ResetFunctionStack(state);
|
||||
if (spawn && player && transport_id && player->IsPlayer()) {
|
||||
Client* client = 0;
|
||||
if (player && player->IsPlayer())
|
||||
|
@ -10748,6 +10791,7 @@ int EQ2Emu_lua_SetTemporaryTransportID(lua_State* state) {
|
|||
Spawn* player = lua_interface->GetSpawn(state);
|
||||
int32 transport_id = lua_interface->GetInt32Value(state, 2);
|
||||
|
||||
lua_interface->ResetFunctionStack(state);
|
||||
if (player && player->IsPlayer()) {
|
||||
Client* client = 0;
|
||||
if (player && player->IsPlayer())
|
||||
|
@ -10765,6 +10809,8 @@ int EQ2Emu_lua_GetTemporaryTransportID(lua_State* state) {
|
|||
if (!lua_interface)
|
||||
return 0;
|
||||
Spawn* player = lua_interface->GetSpawn(state);
|
||||
|
||||
lua_interface->ResetFunctionStack(state);
|
||||
if (player && player->IsPlayer()) {
|
||||
Client* client = 0;
|
||||
if (player && player->IsPlayer())
|
||||
|
@ -10803,6 +10849,8 @@ int EQ2Emu_lua_SetAlignment(lua_State* state) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
lua_interface->ResetFunctionStack(state);
|
||||
|
||||
if (spell && spell->targets.size() > 0) {
|
||||
ZoneServer* zone = spell->caster->GetZone();
|
||||
for (int8 i = 0; i < spell->targets.size(); i++) {
|
||||
|
@ -10827,6 +10875,8 @@ int EQ2Emu_lua_GetAlignment(lua_State* state) {
|
|||
return 0;
|
||||
Spawn* spawn = lua_interface->GetSpawn(state);
|
||||
|
||||
lua_interface->ResetFunctionStack(state);
|
||||
|
||||
if (!spawn) {
|
||||
lua_interface->LogError("%s: LUA GetAlignment command error: spawn is not valid", lua_interface->GetScriptName(state));
|
||||
return 0;
|
||||
|
@ -11264,6 +11314,23 @@ int EQ2Emu_lua_SetInvulnerable(lua_State* state) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int EQ2Emu_lua_GetRuleFlagBool(lua_State* state) {
|
||||
if (!lua_interface)
|
||||
return 0;
|
||||
string category = lua_interface->GetStringValue(state);
|
||||
string name = lua_interface->GetStringValue(state, 2);
|
||||
lua_interface->ResetFunctionStack(state);
|
||||
Rule *ret = 0;
|
||||
if ((ret = rule_manager.GetGlobalRule(category.c_str(), name.c_str()))) {
|
||||
|
||||
lua_interface->SetBooleanValue(state, ret->GetBool());
|
||||
return 1;
|
||||
}
|
||||
|
||||
lua_interface->LogError("%s: LUA GetRuleFlagBool Unknown rule with category '%s' and type '%s'", lua_interface->GetScriptName(state), category.c_str(), name.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EQ2Emu_lua_GetRuleFlagInt32(lua_State* state) {
|
||||
if (!lua_interface)
|
||||
return 0;
|
||||
|
@ -11277,7 +11344,24 @@ int EQ2Emu_lua_GetRuleFlagInt32(lua_State* state) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
lua_interface->LogError("%s: LUA GetRuleFlag Unknown rule with category '%s' and type '%s'", lua_interface->GetScriptName(state), category.c_str(), name.c_str());
|
||||
lua_interface->LogError("%s: LUA GetRuleFlagInt32 Unknown rule with category '%s' and type '%s'", lua_interface->GetScriptName(state), category.c_str(), name.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EQ2Emu_lua_GetRuleFlagFloat(lua_State* state) {
|
||||
if (!lua_interface)
|
||||
return 0;
|
||||
string category = lua_interface->GetStringValue(state);
|
||||
string name = lua_interface->GetStringValue(state, 2);
|
||||
lua_interface->ResetFunctionStack(state);
|
||||
Rule *ret = 0;
|
||||
if ((ret = rule_manager.GetGlobalRule(category.c_str(), name.c_str()))) {
|
||||
|
||||
lua_interface->SetFloatValue(state, ret->GetFloat());
|
||||
return 1;
|
||||
}
|
||||
|
||||
lua_interface->LogError("%s: LUA GetRuleFlagFloat Unknown rule with category '%s' and type '%s'", lua_interface->GetScriptName(state), category.c_str(), name.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -11824,6 +11908,8 @@ int EQ2Emu_lua_IsOpen(lua_State* state) {
|
|||
if (!lua_interface)
|
||||
return 0;
|
||||
Spawn* widget = lua_interface->GetSpawn(state);
|
||||
lua_interface->ResetFunctionStack(state);
|
||||
|
||||
if (widget && widget->IsWidget())
|
||||
{
|
||||
lua_interface->SetBooleanValue(state, ((Widget*)widget)->IsOpen());
|
||||
|
@ -11838,6 +11924,8 @@ int EQ2Emu_lua_MakeRandomInt(lua_State* state) {
|
|||
|
||||
sint32 min = lua_interface->GetSInt32Value(state);
|
||||
sint32 max = lua_interface->GetSInt32Value(state, 2);
|
||||
lua_interface->ResetFunctionStack(state);
|
||||
|
||||
sint32 result = MakeRandomInt(min, max);
|
||||
lua_interface->SetSInt32Value(state, result);
|
||||
return 1;
|
||||
|
@ -11849,6 +11937,8 @@ int EQ2Emu_lua_MakeRandomFloat(lua_State* state) {
|
|||
|
||||
float min = lua_interface->GetFloatValue(state);
|
||||
float max = lua_interface->GetFloatValue(state, 2);
|
||||
lua_interface->ResetFunctionStack(state);
|
||||
|
||||
float result = MakeRandomFloat(min, max);
|
||||
lua_interface->SetFloatValue(state, result);
|
||||
return 1;
|
||||
|
@ -11896,4 +11986,60 @@ int EQ2Emu_lua_RemoveIconValue(lua_State* state) {
|
|||
lua_interface->SetBooleanValue(state, true);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int EQ2Emu_lua_GetShardID(lua_State* state) {
|
||||
Spawn* npc = lua_interface->GetSpawn(state);
|
||||
lua_interface->ResetFunctionStack(state);
|
||||
|
||||
if (npc && npc->IsNPC()) {
|
||||
NPC* shard = (NPC*)npc;
|
||||
int32 shardid = shard->GetShardID();
|
||||
lua_interface->SetInt32Value(state, shardid);
|
||||
return 1;
|
||||
}
|
||||
lua_interface->SetInt32Value(state, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EQ2Emu_lua_GetShardCharID(lua_State* state) {
|
||||
Spawn* npc = lua_interface->GetSpawn(state);
|
||||
lua_interface->ResetFunctionStack(state);
|
||||
|
||||
if (npc && npc->IsNPC()) {
|
||||
NPC* shard = (NPC*)npc;
|
||||
int32 charid = shard->GetShardCharID();
|
||||
lua_interface->SetInt32Value(state, charid);
|
||||
return 1;
|
||||
}
|
||||
lua_interface->SetInt32Value(state, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EQ2Emu_lua_GetShardCreatedTimestamp(lua_State* state) {
|
||||
Spawn* npc = lua_interface->GetSpawn(state);
|
||||
lua_interface->ResetFunctionStack(state);
|
||||
|
||||
if (npc && npc->IsNPC()) {
|
||||
NPC* shard = (NPC*)npc;
|
||||
int64 timestamp = shard->GetShardCreatedTimestamp();
|
||||
lua_interface->SetSInt64Value(state, timestamp);
|
||||
return 1;
|
||||
}
|
||||
lua_interface->SetSInt64Value(state, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EQ2Emu_lua_DeleteDBShardID(lua_State* state) {
|
||||
if (!lua_interface)
|
||||
return 0;
|
||||
int32 shardid = lua_interface->GetInt32Value(state);
|
||||
|
||||
lua_interface->ResetFunctionStack(state);
|
||||
|
||||
if(shardid < 1)
|
||||
lua_interface->SetBooleanValue(state, false);
|
||||
else
|
||||
lua_interface->SetBooleanValue(state, database.DeleteSpiritShard(shardid));
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -183,6 +183,7 @@ int EQ2Emu_lua_Shout(lua_State* state);
|
|||
int EQ2Emu_lua_SayOOC(lua_State* state);
|
||||
int EQ2Emu_lua_Emote(lua_State* state);
|
||||
int EQ2Emu_lua_IsPlayer(lua_State* state);
|
||||
int EQ2Emu_lua_GetCharacterID(lua_State* state);
|
||||
int EQ2Emu_lua_MovementLoopAdd(lua_State* state);
|
||||
int EQ2Emu_lua_GetCurrentZoneSafeLocation(lua_State* state);
|
||||
int EQ2Emu_lua_PlayFlavor(lua_State* state);
|
||||
|
@ -497,6 +498,7 @@ int EQ2Emu_lua_SetSeeInvis(lua_State* state);
|
|||
int EQ2Emu_lua_SetSeeHide(lua_State* state);
|
||||
|
||||
int EQ2Emu_lua_SetAccessToEntityCommand(lua_State* state);
|
||||
int EQ2Emu_lua_SetAccessToEntityCommandByCharID(lua_State* state);
|
||||
int EQ2Emu_lua_RemovePrimaryEntityCommand(lua_State* state);
|
||||
int EQ2Emu_lua_SendUpdateDefaultCommand(lua_State* state);
|
||||
|
||||
|
@ -527,7 +529,9 @@ int EQ2Emu_lua_DamageSpawn(lua_State* state);
|
|||
int EQ2Emu_lua_IsInvulnerable(lua_State* state);
|
||||
int EQ2Emu_lua_SetInvulnerable(lua_State* state);
|
||||
|
||||
int EQ2Emu_lua_GetRuleFlagBool(lua_State* state);
|
||||
int EQ2Emu_lua_GetRuleFlagInt32(lua_State* state);
|
||||
int EQ2Emu_lua_GetRuleFlagFloat(lua_State* state);
|
||||
|
||||
int EQ2Emu_lua_GetAAInfo(lua_State* state);
|
||||
int EQ2Emu_lua_SetAAInfo(lua_State* state);
|
||||
|
@ -563,4 +567,9 @@ int EQ2Emu_lua_MakeRandomFloat(lua_State* state);
|
|||
|
||||
int EQ2Emu_lua_AddIconValue(lua_State* state);
|
||||
int EQ2Emu_lua_RemoveIconValue(lua_State* state);
|
||||
|
||||
int EQ2Emu_lua_GetShardID(lua_State* state);
|
||||
int EQ2Emu_lua_GetShardCharID(lua_State* state);
|
||||
int EQ2Emu_lua_GetShardCreatedTimestamp(lua_State* state);
|
||||
int EQ2Emu_lua_DeleteDBShardID(lua_State* state);
|
||||
#endif
|
|
@ -843,6 +843,7 @@ void LuaInterface::RegisterFunctions(lua_State* state) {
|
|||
|
||||
|
||||
lua_register(state, "IsPlayer", EQ2Emu_lua_IsPlayer);
|
||||
lua_register(state, "GetCharacterID", EQ2Emu_lua_GetCharacterID);
|
||||
lua_register(state, "FaceTarget", EQ2Emu_lua_FaceTarget);
|
||||
lua_register(state, "MoveToLocation", EQ2Emu_lua_MoveToLocation);
|
||||
lua_register(state, "ClearRunningLocations", EQ2Emu_lua_ClearRunningLocations);
|
||||
|
@ -1213,6 +1214,7 @@ void LuaInterface::RegisterFunctions(lua_State* state) {
|
|||
lua_register(state, "SetSeeHide", EQ2Emu_lua_SetSeeHide);
|
||||
|
||||
lua_register(state, "SetAccessToEntityCommand", EQ2Emu_lua_SetAccessToEntityCommand);
|
||||
lua_register(state, "SetAccessToEntityCommandByCharID", EQ2Emu_lua_SetAccessToEntityCommandByCharID);
|
||||
lua_register(state, "RemovePrimaryEntityCommand", EQ2Emu_lua_RemovePrimaryEntityCommand);
|
||||
lua_register(state, "SendUpdateDefaultCommand", EQ2Emu_lua_SendUpdateDefaultCommand);
|
||||
|
||||
|
@ -1241,7 +1243,9 @@ void LuaInterface::RegisterFunctions(lua_State* state) {
|
|||
lua_register(state, "IsInvulnerable", EQ2Emu_lua_IsInvulnerable);
|
||||
lua_register(state, "SetInvulnerable", EQ2Emu_lua_SetInvulnerable);
|
||||
|
||||
lua_register(state, "GetRuleFlagBool", EQ2Emu_lua_GetRuleFlagBool);
|
||||
lua_register(state, "GetRuleFlagInt32", EQ2Emu_lua_GetRuleFlagInt32);
|
||||
lua_register(state, "GetRuleFlagFloat", EQ2Emu_lua_GetRuleFlagFloat);
|
||||
|
||||
lua_register(state, "GetAAInfo", EQ2Emu_lua_GetAAInfo);
|
||||
lua_register(state, "SetAAInfo", EQ2Emu_lua_SetAAInfo);
|
||||
|
@ -1277,6 +1281,11 @@ void LuaInterface::RegisterFunctions(lua_State* state) {
|
|||
|
||||
lua_register(state, "AddIconValue", EQ2Emu_lua_AddIconValue);
|
||||
lua_register(state, "RemoveIconValue", EQ2Emu_lua_RemoveIconValue);
|
||||
|
||||
lua_register(state, "GetShardID", EQ2Emu_lua_GetShardID);
|
||||
lua_register(state, "GetShardCharID", EQ2Emu_lua_GetShardCharID);
|
||||
lua_register(state, "GetShardCreatedTimestamp", EQ2Emu_lua_GetShardCreatedTimestamp);
|
||||
lua_register(state, "DeleteDBShardID", EQ2Emu_lua_DeleteDBShardID);
|
||||
}
|
||||
|
||||
void LuaInterface::LogError(const char* error, ...) {
|
||||
|
|
|
@ -143,6 +143,9 @@ void NPC::Initialize(){
|
|||
following = false;
|
||||
SetFollowTarget(0);
|
||||
m_petDismissing = false;
|
||||
m_ShardID = 0;
|
||||
m_ShardCharID = 0;
|
||||
m_ShardCreatedTimestamp = 0;
|
||||
}
|
||||
|
||||
EQ2Packet* NPC::serialize(Player* player, int16 version){
|
||||
|
|
|
@ -146,6 +146,14 @@ public:
|
|||
bool IsDismissing() { return m_petDismissing; }
|
||||
void SetDismissing(bool val) { m_petDismissing = val; }
|
||||
|
||||
int32 GetShardID() { return m_ShardID; }
|
||||
void SetShardID(int32 shardid) { m_ShardID = shardid; }
|
||||
|
||||
int32 GetShardCharID() { return m_ShardCharID; }
|
||||
void SetShardCharID(int32 charid) { m_ShardCharID = charid; }
|
||||
|
||||
sint64 GetShardCreatedTimestamp() { return m_ShardCreatedTimestamp; }
|
||||
void SetShardCreatedTimestamp(sint64 timestamp) { m_ShardCreatedTimestamp = timestamp; }
|
||||
private:
|
||||
MovementLocation* runback;
|
||||
int8 cast_percentage;
|
||||
|
@ -177,6 +185,10 @@ private:
|
|||
// the brain class and not the function defined above
|
||||
::Brain* m_brain;
|
||||
Mutex MBrain;
|
||||
|
||||
int32 m_ShardID;
|
||||
int32 m_ShardCharID;
|
||||
sint64 m_ShardCreatedTimestamp;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
|
|
@ -759,7 +759,19 @@ EQ2Packet* PlayerInfo::serialize(int16 version, int16 modifyPos, int32 modifyVal
|
|||
CalculateXPPercentages();
|
||||
packet->setDataByName("current_adv_xp", info_struct->get_xp()); // confirmed DoV
|
||||
packet->setDataByName("needed_adv_xp", info_struct->get_xp_needed());// confirmed DoV
|
||||
packet->setDataByName("debt_adv_xp", info_struct->get_xp_debt());//95= 9500% //confirmed DoV
|
||||
|
||||
if(version >= 60114)
|
||||
{
|
||||
// AoM ends up the debt_adv_xp field is the percentage of xp to the next level needed to advance out of debt (WHYY CANT THIS JUST BE A PERCENTAGE LIKE DOV!)
|
||||
float currentPctOfLevel = (float)info_struct->get_xp() / (float)info_struct->get_xp_needed();
|
||||
float neededPctAdvanceOutOfDebt = currentPctOfLevel + (info_struct->get_xp_debt() / 100.0f);
|
||||
packet->setDataByName("debt_adv_xp", neededPctAdvanceOutOfDebt);
|
||||
}
|
||||
else
|
||||
{
|
||||
packet->setDataByName("exp_debt", (int16)(info_struct->get_xp_debt()/10.0f));//95= 9500% //confirmed DoV
|
||||
}
|
||||
|
||||
packet->setDataByName("current_trade_xp", info_struct->get_ts_xp());// confirmed DoV
|
||||
packet->setDataByName("needed_trade_xp", info_struct->get_ts_xp_needed());// confirmed DoV
|
||||
|
||||
|
@ -1431,9 +1443,12 @@ EQ2Packet* PlayerInfo::serialize(int16 version, int16 modifyPos, int32 modifyVal
|
|||
}
|
||||
}
|
||||
player->GetDetrimentMutex()->releasereadlock(__FUNCTION__, __LINE__);
|
||||
packet->setDataByName("spirit_rank", 2);
|
||||
packet->setDataByName("spirit", 1);
|
||||
packet->setDataByName("spirit_progress", .67);
|
||||
|
||||
// disabling as not in use right now
|
||||
//packet->setDataByName("spirit_rank", 2);
|
||||
//packet->setDataByName("spirit", 1);
|
||||
//packet->setDataByName("spirit_progress", .67);
|
||||
|
||||
packet->setDataByName("combat_exp_enabled", 1);
|
||||
/*for (int i = 0; i < 12; i++) {
|
||||
packet->setSubstructDataByName("spell_effects", "spell_id", i + 1, i);
|
||||
|
@ -3777,6 +3792,35 @@ float Player::CalculateTSXP(int8 level){
|
|||
return total * world.GetXPRate() * zone_xp_modifier;
|
||||
}
|
||||
|
||||
void Player::CalculateOfflineDebtRecovery(int32 unix_timestamp)
|
||||
{
|
||||
float xpDebt = GetXPDebt();
|
||||
// not a real timestamp to work with
|
||||
if(unix_timestamp < 1 || xpDebt == 0.0f)
|
||||
return;
|
||||
|
||||
uint32 diff = (Timer::GetCurrentTime2() - unix_timestamp)/1000;
|
||||
|
||||
float recoveryDebtPercentage = rule_manager.GetGlobalRule(R_Combat, ExperienceDebtRecoveryPercent)->GetFloat()/100.0f;
|
||||
int32 recoveryPeriodSeconds = rule_manager.GetGlobalRule(R_Combat, ExperienceDebtRecoveryPeriod)->GetInt32();
|
||||
if(recoveryDebtPercentage == 0.0f || recoveryPeriodSeconds < 1)
|
||||
return;
|
||||
|
||||
|
||||
float periodsPassed = (float)diff/(float)recoveryPeriodSeconds;
|
||||
|
||||
// not enough time passed to calculate debt xp recovered
|
||||
if(periodsPassed < 1.0f)
|
||||
return;
|
||||
|
||||
float debtToSubtract = xpDebt * ((recoveryDebtPercentage*periodsPassed)/100.0f);
|
||||
|
||||
if(debtToSubtract >= xpDebt)
|
||||
GetInfoStruct()->set_xp_debt(0.0f);
|
||||
else
|
||||
GetInfoStruct()->set_xp_debt(xpDebt - debtToSubtract);
|
||||
}
|
||||
|
||||
void Player::SetNeededXP(int32 val){
|
||||
GetInfoStruct()->set_xp_needed(val);
|
||||
}
|
||||
|
@ -3808,7 +3852,7 @@ void Player::SetTSXP(int32 val) {
|
|||
GetInfoStruct()->set_ts_xp(val);
|
||||
}
|
||||
|
||||
int32 Player::GetXPDebt(){
|
||||
float Player::GetXPDebt(){
|
||||
return GetInfoStruct()->get_xp_debt();
|
||||
}
|
||||
|
||||
|
@ -3830,9 +3874,38 @@ int32 Player::GetTSXP() {
|
|||
|
||||
bool Player::AddXP(int32 xp_amount){
|
||||
MStats.lock();
|
||||
xp_amount += ((xp_amount) * stats[ITEM_STAT_COMBATEXPMOD]) / 100;
|
||||
xp_amount += (int32)(((float)xp_amount) * stats[ITEM_STAT_COMBATEXPMOD]) / 100;
|
||||
MStats.unlock();
|
||||
|
||||
if(GetInfoStruct()->get_xp_debt())
|
||||
{
|
||||
float expRatioToDebt = rule_manager.GetGlobalRule(R_Combat, ExperienceToDebt)->GetFloat()/100.0f;
|
||||
int32 amountToTakeFromDebt = (int32)((float)expRatioToDebt * (float)xp_amount);
|
||||
int32 amountRequiredClearDebt = (GetInfoStruct()->get_xp_debt()/100.0f) * xp_amount;
|
||||
|
||||
if(amountToTakeFromDebt > amountRequiredClearDebt)
|
||||
{
|
||||
GetInfoStruct()->set_xp_debt(0.0f);
|
||||
if(amountRequiredClearDebt > xp_amount)
|
||||
xp_amount = 0;
|
||||
else
|
||||
xp_amount -= amountRequiredClearDebt;
|
||||
}
|
||||
else
|
||||
{
|
||||
float amountRemovedPct = ((float)amountToTakeFromDebt/(float)amountRequiredClearDebt);
|
||||
GetInfoStruct()->set_xp_debt(GetInfoStruct()->get_xp_debt()-amountRemovedPct);
|
||||
if(amountToTakeFromDebt > xp_amount)
|
||||
xp_amount = 0;
|
||||
else
|
||||
xp_amount -= amountToTakeFromDebt;
|
||||
}
|
||||
}
|
||||
|
||||
// used up in xp debt
|
||||
if(!xp_amount)
|
||||
return true;
|
||||
|
||||
float current_xp_percent = ((float)GetXP()/(float)GetNeededXP())*100;
|
||||
float miniding_min_percent = ((int)(current_xp_percent/10)+1)*10;
|
||||
while((xp_amount + GetXP()) >= GetNeededXP()){
|
||||
|
@ -6155,4 +6228,82 @@ void Player::SetSpawnMap(Spawn* spawn)
|
|||
|
||||
player_spawn_reverse_id_map.insert(make_pair(spawn,tmp_id));
|
||||
index_mutex.releasewritelock(__FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
NPC* Player::InstantiateSpiritShard(float origX, float origY, float origZ, float origHeading, int32 origGridID, ZoneServer* origZone)
|
||||
{
|
||||
NPC* npc = new NPC();
|
||||
string newName(GetName());
|
||||
newName.append("'s spirit shard");
|
||||
|
||||
strcpy(npc->appearance.name, newName.c_str());
|
||||
/*vector<EntityCommand*>* primary_command_list = zone->GetEntityCommandList(result.GetInt32(9));
|
||||
vector<EntityCommand*>* secondary_command_list = zone->GetEntityCommandList(result.GetInt32(10));
|
||||
if(primary_command_list){
|
||||
npc->SetPrimaryCommands(primary_command_list);
|
||||
npc->primary_command_list_id = result.GetInt32(9);
|
||||
}
|
||||
if(secondary_command_list){
|
||||
npc->SetSecondaryCommands(secondary_command_list);
|
||||
npc->secondary_command_list_id = result.GetInt32(10);
|
||||
}*/
|
||||
npc->appearance.level = GetLevel();
|
||||
npc->appearance.race = GetRace();
|
||||
npc->appearance.gender = GetGender();
|
||||
npc->appearance.adventure_class = GetAdventureClass();
|
||||
|
||||
//npc->appearance.lua_race_id = result.GetInt16(74);
|
||||
npc->appearance.model_type = GetModelType();
|
||||
npc->appearance.soga_model_type = GetSogaModelType();
|
||||
npc->appearance.display_name = 1;
|
||||
npc->features.hair_type = GetHairType();
|
||||
npc->features.hair_face_type = GetFacialHairType();
|
||||
npc->features.wing_type = GetWingType();
|
||||
npc->features.chest_type = GetChestType();
|
||||
npc->features.legs_type = GetLegsType();
|
||||
npc->features.soga_hair_type = GetSogaHairType();
|
||||
npc->features.soga_hair_face_type = GetSogaFacialHairType();
|
||||
npc->appearance.attackable = 0;
|
||||
npc->appearance.show_level = 1;
|
||||
npc->appearance.targetable = 1;
|
||||
npc->appearance.show_command_icon = 1;
|
||||
npc->appearance.display_hand_icon = 0;
|
||||
npc->appearance.hide_hood = GetHideHood();
|
||||
npc->size = GetSize();
|
||||
npc->appearance.pos.collision_radius = appearance.pos.collision_radius;
|
||||
npc->appearance.action_state = appearance.action_state;
|
||||
npc->appearance.visual_state = 6193; // ghostly look
|
||||
npc->appearance.mood_state = appearance.mood_state;
|
||||
npc->appearance.emote_state = appearance.emote_state;
|
||||
npc->appearance.pos.state = appearance.pos.state;
|
||||
npc->appearance.activity_status = appearance.activity_status;
|
||||
strncpy(npc->appearance.sub_title, appearance.sub_title, sizeof(npc->appearance.sub_title));
|
||||
npc->SetPrefixTitle(GetPrefixTitle());
|
||||
npc->SetSuffixTitle(GetSuffixTitle());
|
||||
npc->SetLastName(GetLastName());
|
||||
npc->SetX(origX);
|
||||
npc->SetY(origY);
|
||||
npc->SetZ(origZ);
|
||||
npc->SetHeading(origHeading);
|
||||
npc->SetSpawnOrigX(origX);
|
||||
npc->SetSpawnOrigY(origY);
|
||||
npc->SetSpawnOrigZ(origZ);
|
||||
npc->SetSpawnOrigHeading(origHeading);
|
||||
npc->appearance.pos.grid_id = origGridID;
|
||||
const char* script = rule_manager.GetGlobalRule(R_Combat, SpiritShardSpawnScript)->GetString();
|
||||
|
||||
int32 dbid = database.CreateSpiritShard(newName.c_str(), GetLevel(), GetRace(), GetGender(), GetAdventureClass(), GetModelType(), GetSogaModelType(),
|
||||
GetHairType(), GetFacialHairType(), GetWingType(), GetChestType(), GetLegsType(), GetSogaHairType(), GetSogaFacialHairType(), GetHideHood(),
|
||||
GetSize(), npc->appearance.pos.collision_radius, npc->appearance.action_state, npc->appearance.visual_state, npc->appearance.mood_state,
|
||||
npc->appearance.emote_state, npc->appearance.pos.state, npc->appearance.activity_status, npc->appearance.sub_title, GetPrefixTitle(), GetSuffixTitle(),
|
||||
GetLastName(), origX, origY, origZ, origHeading, origGridID, GetCharacterID(), origZone->GetZoneID(), origZone->GetInstanceID());
|
||||
|
||||
npc->SetShardID(dbid);
|
||||
npc->SetShardCharID(GetCharacterID());
|
||||
npc->SetShardCreatedTimestamp(Timer::GetCurrentTime2());
|
||||
|
||||
if(script)
|
||||
npc->SetSpawnScript(script);
|
||||
|
||||
return npc;
|
||||
}
|
|
@ -530,7 +530,7 @@ public:
|
|||
void SetNeededTSXP();
|
||||
void SetTSXP(int32 val);
|
||||
int32 GetNeededXP();
|
||||
int32 GetXPDebt();
|
||||
float GetXPDebt();
|
||||
int32 GetXP();
|
||||
int32 GetNeededTSXP();
|
||||
int32 GetTSXP();
|
||||
|
@ -539,6 +539,7 @@ public:
|
|||
bool DoubleXPEnabled();
|
||||
float CalculateXP(Spawn* victim);
|
||||
float CalculateTSXP(int8 level);
|
||||
void CalculateOfflineDebtRecovery(int32 unix_timestamp);
|
||||
void InCombat(bool val, bool range = false);
|
||||
void PrepareIncomingMovementPacket(int32 len, uchar* data, int16 version);
|
||||
uchar* GetMovementPacketData(){
|
||||
|
@ -956,6 +957,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
NPC* InstantiateSpiritShard(float origX, float origY, float origZ, float origHeading, int32 origGridID, ZoneServer* origZone);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -218,6 +218,17 @@ void RuleManager::Init()
|
|||
|
||||
/* COMBAT */
|
||||
RULE_INIT(R_Combat, MaxCombatRange, "4.0");
|
||||
RULE_INIT(R_Combat, DeathExperienceDebt, "50.00"); // divide by 100, 50/100 = .5% debt per pve death
|
||||
RULE_INIT(R_Combat, PVPDeathExperienceDebt, "25.00"); // divide by 100, 25/100 = .25% debt per pvp death
|
||||
RULE_INIT(R_Combat, GroupExperienceDebt, "0"); // set to 1 means we will share debt between the group
|
||||
RULE_INIT(R_Combat, ExperienceToDebt, "50.00"); // percentage of xp earned to debt vs obtained xp 50/100 = 50% to debt
|
||||
RULE_INIT(R_Combat, ExperienceDebtRecoveryPercent, "5.00"); // recovery percentage per period of time, 5/100 = 5% recovered (so if .5% debt, .5*.05 = .025, .5-.025=.475% debt left)
|
||||
RULE_INIT(R_Combat, ExperienceDebtRecoveryPeriod, "600"); // every 10 minutes (x*60 seconds) recover ExperienceDebtRecoveryPercent
|
||||
RULE_INIT(R_Combat, EnableSpiritShards, "1");
|
||||
RULE_INIT(R_Combat, SpiritShardSpawnScript, "SpawnScripts/Generic/SpiritShard.lua");
|
||||
RULE_INIT(R_Combat, ShardDebtRecoveryPercent, "25.00"); // recovered percentage of debt upon obtainig shard, 25/100 means 25%. If there is .5 DeathExperienceDebt, .5*25% = .125, .5 - .125 = .375
|
||||
RULE_INIT(R_Combat, ShardRecoveryByRadius, "1"); // allow shards to auto pick up by radius, not requiring to click/right click the shard
|
||||
|
||||
/* SPAWN */
|
||||
RULE_INIT(R_Spawn, SpeedMultiplier, "300"); // note: this value was 1280 until 6/1/2009, then was 600 til Sep 2009, when it became 300...?
|
||||
RULE_INIT(R_Spawn, ClassicRegen, "0");
|
||||
|
|
|
@ -78,6 +78,16 @@ enum RuleType {
|
|||
|
||||
/* COMBAT */
|
||||
MaxCombatRange,
|
||||
DeathExperienceDebt,
|
||||
GroupExperienceDebt,
|
||||
PVPDeathExperienceDebt,
|
||||
ExperienceToDebt,
|
||||
ExperienceDebtRecoveryPercent,
|
||||
ExperienceDebtRecoveryPeriod,
|
||||
EnableSpiritShards,
|
||||
SpiritShardSpawnScript,
|
||||
ShardDebtRecoveryPercent,
|
||||
ShardRecoveryByRadius,
|
||||
|
||||
/* SPAWN */
|
||||
SpeedMultiplier,
|
||||
|
|
|
@ -3849,18 +3849,21 @@ void Spawn::RemovePrimaryEntityCommand(const char* command) {
|
|||
|
||||
bool Spawn::SetPermissionToEntityCommand(EntityCommand* command, Player* player, bool permissionValue)
|
||||
{
|
||||
if (player != NULL)
|
||||
{
|
||||
map<int32, bool>::iterator itr = command->allow_or_deny.find(player->GetCharacterID());
|
||||
if (itr == command->allow_or_deny.end())
|
||||
command->allow_or_deny.insert(make_pair(player->GetCharacterID(), permissionValue));
|
||||
else if (itr->second != permissionValue)
|
||||
itr->second = permissionValue;
|
||||
if(!player)
|
||||
return false;
|
||||
|
||||
return SetPermissionToEntityCommandByCharID(command, player->GetCharacterID(), permissionValue);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
bool Spawn::SetPermissionToEntityCommandByCharID(EntityCommand* command, int32 charID, bool permissionValue)
|
||||
{
|
||||
map<int32, bool>::iterator itr = command->allow_or_deny.find(charID);
|
||||
if (itr == command->allow_or_deny.end())
|
||||
command->allow_or_deny.insert(make_pair(charID, permissionValue));
|
||||
else if (itr->second != permissionValue)
|
||||
itr->second = permissionValue;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Spawn::RemoveSpawnFromPlayer(Player* player)
|
||||
|
|
|
@ -314,6 +314,7 @@ public:
|
|||
void AddPrimaryEntityCommand(const char* name, float distance, const char* command, const char* error_text, int16 cast_time, int32 spell_visual, bool defaultDenyList = false, Player* player = NULL);
|
||||
void RemovePrimaryEntityCommand(const char* command);
|
||||
bool SetPermissionToEntityCommand(EntityCommand* command, Player* player, bool permissionValue);
|
||||
bool SetPermissionToEntityCommandByCharID(EntityCommand* command, int32 charID, bool permissionValue);
|
||||
|
||||
void RemoveSpawnFromPlayer(Player* player);
|
||||
|
||||
|
|
|
@ -1064,6 +1064,112 @@ void WorldDatabase::LoadNPCs(ZoneServer* zone){
|
|||
LogWrite(NPC__INFO, 0, "NPC", "--Loaded %i NPC Equipment Appearance(s).", LoadNPCAppearanceEquipmentData(zone));
|
||||
}
|
||||
|
||||
|
||||
void WorldDatabase::LoadSpiritShards(ZoneServer* zone){
|
||||
Query query;
|
||||
MYSQL_ROW row;
|
||||
NPC* npc = 0;
|
||||
int32 id = 0;
|
||||
int32 total = 0;
|
||||
MYSQL_RES* result = query.RunQuery2(Q_SELECT,"SELECT timestamp, name, level, race, gender, adventure_class, model_type, soga_model_type, hair_type, hair_face_type, wing_type, chest_type, legs_type, soga_hair_type, soga_hair_face_type, hide_hood, size, collision_radius, action_state, visual_state, mood_state, emote_state, pos_state, activity_status, sub_title, prefix_title, suffix_title, lastname, x, y, z, heading, gridid, id, charid\n"
|
||||
"FROM character_spirit_shards\n"
|
||||
"WHERE zoneid = %u and (instanceid = 0 or instanceid = %u)",
|
||||
zone->GetZoneID(), zone->GetInstanceID());
|
||||
while(result && (row = mysql_fetch_row(result))){
|
||||
/*npc->SetAppearanceID(atoi(row[12]));
|
||||
AppearanceData* appearance = world.GetNPCAppearance(npc->GetAppearanceID());
|
||||
if(appearance)
|
||||
memcpy(&npc->appearance, appearance, sizeof(AppearanceData));
|
||||
*/
|
||||
sint64 timestamp = 0;
|
||||
#ifdef WIN32
|
||||
timestamp = _strtoui64(row[0], NULL, 10);
|
||||
#else
|
||||
timestamp = strtoull(row[0], 0, 10);
|
||||
#endif
|
||||
|
||||
if(!row[1])
|
||||
continue;
|
||||
|
||||
NPC* shard = new NPC();
|
||||
|
||||
shard->SetShardCreatedTimestamp(timestamp);
|
||||
strcpy(shard->appearance.name, row[1]);
|
||||
|
||||
shard->appearance.level = atoul(row[2]);
|
||||
shard->appearance.race = atoul(row[3]);
|
||||
shard->appearance.gender = atoul(row[4]);
|
||||
shard->appearance.adventure_class = atoul(row[5]);
|
||||
|
||||
//shard->appearance.lua_race_id = result.GetInt16(74);
|
||||
shard->appearance.model_type = atoul(row[6]);
|
||||
shard->appearance.soga_model_type = atoul(row[7]);
|
||||
shard->appearance.display_name = 1;
|
||||
shard->features.hair_type = atoul(row[8]);
|
||||
shard->features.hair_face_type = atoul(row[9]);
|
||||
shard->features.wing_type = atoul(row[10]);
|
||||
shard->features.chest_type = atoul(row[11]);
|
||||
shard->features.legs_type = atoul(row[12]);
|
||||
shard->features.soga_hair_type = atoul(row[13]);
|
||||
shard->features.soga_hair_face_type = atoul(row[14]);
|
||||
shard->appearance.attackable = 0;
|
||||
shard->appearance.show_level = 1;
|
||||
shard->appearance.targetable = 1;
|
||||
shard->appearance.show_command_icon = 1;
|
||||
shard->appearance.display_hand_icon = 0;
|
||||
shard->appearance.hide_hood = atoul(row[15]);
|
||||
shard->size = atoul(row[16]);
|
||||
shard->appearance.pos.collision_radius = atoul(row[17]);
|
||||
shard->appearance.action_state = atoul(row[18]);
|
||||
shard->appearance.visual_state = atoul(row[19]); // ghostly look
|
||||
shard->appearance.mood_state = atoul(row[20]);
|
||||
shard->appearance.emote_state = atoul(row[21]);
|
||||
shard->appearance.pos.state = atoul(row[22]);
|
||||
shard->appearance.activity_status = atoul(row[23]);
|
||||
|
||||
if(row[24])
|
||||
strncpy(shard->appearance.sub_title, row[24], sizeof(shard->appearance.sub_title));
|
||||
|
||||
if(row[25])
|
||||
shard->SetPrefixTitle(row[25]);
|
||||
|
||||
if(row[26])
|
||||
shard->SetSuffixTitle(row[26]);
|
||||
|
||||
if(row[27])
|
||||
shard->SetLastName(row[27]);
|
||||
|
||||
shard->SetX(atof(row[28]));
|
||||
shard->SetY(atof(row[29]));
|
||||
shard->SetZ(atof(row[30]));
|
||||
shard->SetHeading(atof(row[31]));
|
||||
shard->SetSpawnOrigX(shard->GetX());
|
||||
shard->SetSpawnOrigY(shard->GetY());
|
||||
shard->SetSpawnOrigZ(shard->GetZ());
|
||||
shard->SetSpawnOrigHeading(shard->GetHeading());
|
||||
shard->appearance.pos.grid_id = atoul(row[32]);
|
||||
shard->SetShardID(atoul(row[33]));
|
||||
shard->SetShardCharID(atoul(row[34]));
|
||||
|
||||
const char* script = rule_manager.GetGlobalRule(R_Combat, SpiritShardSpawnScript)->GetString();
|
||||
|
||||
if(script)
|
||||
{
|
||||
shard->SetSpawnScript(script);
|
||||
zone->CallSpawnScript(shard, SPAWN_SCRIPT_PRESPAWN);
|
||||
}
|
||||
|
||||
zone->AddSpawn(shard);
|
||||
|
||||
if(script)
|
||||
zone->CallSpawnScript(shard, SPAWN_SCRIPT_SPAWN);
|
||||
|
||||
total++;
|
||||
LogWrite(NPC__DEBUG, 5, "NPC", "---Loading Player Spirit Shard: '%s' (%u)", npc->appearance.name, id);
|
||||
}
|
||||
LogWrite(NPC__INFO, 0, "NPC", "--Loaded %i Spirit Shard(s).", total);
|
||||
}
|
||||
|
||||
void WorldDatabase::LoadSigns(ZoneServer* zone){
|
||||
Query query;
|
||||
MYSQL_ROW row;
|
||||
|
@ -1513,7 +1619,7 @@ bool WorldDatabase::LoadCharacterStats(int32 id, int32 account_id, Client* clien
|
|||
if(info->get_xp_needed()== 0)
|
||||
client->GetPlayer()->SetNeededXP();
|
||||
|
||||
info->set_xp_debt(result.GetInt32Str("xp_debt"));
|
||||
info->set_xp_debt(result.GetFloatStr("xp_debt"));
|
||||
info->set_xp_vitality(result.GetFloatStr("xp_vitality"));
|
||||
info->set_ts_xp(result.GetInt32Str("tradeskill_xp"));
|
||||
info->set_ts_xp_needed(result.GetInt32Str("tradeskill_xp_needed"));
|
||||
|
@ -3810,7 +3916,7 @@ void WorldDatabase::Save(Client* client){
|
|||
if(client->GetCurrentZone())
|
||||
zone_id = client->GetCurrentZone()->GetZoneID();
|
||||
query.AddQueryAsync(client->GetCharacterID(), this, Q_UPDATE, "update characters set current_zone_id=%u, x=%f, y=%f, z=%f, heading=%f, level=%i,instance_id=%i,last_saved=%i, `class`=%i, `tradeskill_level`=%i, `tradeskill_class`=%i, `group_id`=%u where id = %u", zone_id, player->GetX(), player->GetY(), player->GetZ(), player->GetHeading(), player->GetLevel(), instance_id, client->GetLastSavedTimeStamp(), client->GetPlayer()->GetAdventureClass(), client->GetPlayer()->GetTSLevel(), client->GetPlayer()->GetTradeskillClass(), client->GetPlayer()->GetGroupMemberInfo() ? client->GetPlayer()->GetGroupMemberInfo()->group_id : 0, client->GetCharacterID());
|
||||
query.AddQueryAsync(client->GetCharacterID(), this, Q_UPDATE, "update character_details set hp=%u, power=%u, str=%i, sta=%i, agi=%i, wis=%i, intel=%i, heat=%i, cold=%i, magic=%i, mental=%i, divine=%i, disease=%i, poison=%i, coin_copper=%u, coin_silver=%u, coin_gold=%u, coin_plat=%u, max_hp = %u, max_power=%u, xp = %u, xp_needed = %u, xp_debt = %u, xp_vitality = %f, tradeskill_xp = %u, tradeskill_xp_needed = %u, tradeskill_xp_vitality = %f, bank_copper = %u, bank_silver = %u, bank_gold = %u, bank_plat = %u, bind_zone_id=%u, bind_x = %f, bind_y = %f, bind_z = %f, bind_heading = %f, house_zone_id=%u, combat_voice = %i, emote_voice = %i, biography='%s', flags=%u, flags2=%u, last_name='%s', assigned_aa = %i, unassigned_aa = %i, tradeskill_aa = %i, unassigned_tradeskill_aa = %i, prestige_aa = %i, unassigned_prestige_aa = %i, tradeskill_prestige_aa = %i, unassigned_tradeskill_prestige_aa = %i where char_id = %u",
|
||||
query.AddQueryAsync(client->GetCharacterID(), this, Q_UPDATE, "update character_details set hp=%u, power=%u, str=%i, sta=%i, agi=%i, wis=%i, intel=%i, heat=%i, cold=%i, magic=%i, mental=%i, divine=%i, disease=%i, poison=%i, coin_copper=%u, coin_silver=%u, coin_gold=%u, coin_plat=%u, max_hp = %u, max_power=%u, xp = %u, xp_needed = %u, xp_debt = %f, xp_vitality = %f, tradeskill_xp = %u, tradeskill_xp_needed = %u, tradeskill_xp_vitality = %f, bank_copper = %u, bank_silver = %u, bank_gold = %u, bank_plat = %u, bind_zone_id=%u, bind_x = %f, bind_y = %f, bind_z = %f, bind_heading = %f, house_zone_id=%u, combat_voice = %i, emote_voice = %i, biography='%s', flags=%u, flags2=%u, last_name='%s', assigned_aa = %i, unassigned_aa = %i, tradeskill_aa = %i, unassigned_tradeskill_aa = %i, prestige_aa = %i, unassigned_prestige_aa = %i, tradeskill_prestige_aa = %i, unassigned_tradeskill_prestige_aa = %i where char_id = %u",
|
||||
player->GetHP(), player->GetPower(), player->GetStrBase(), player->GetStaBase(), player->GetAgiBase(), player->GetWisBase(), player->GetIntBase(), player->GetHeatResistanceBase(), player->GetColdResistanceBase(), player->GetMagicResistanceBase(),
|
||||
player->GetMentalResistanceBase(), player->GetDivineResistanceBase(), player->GetDiseaseResistanceBase(), player->GetPoisonResistanceBase(), player->GetCoinsCopper(), player->GetCoinsSilver(), player->GetCoinsGold(), player->GetCoinsPlat(), player->GetTotalHPBase(), player->GetTotalPowerBase(), player->GetXP(), player->GetNeededXP(), player->GetXPDebt(), player->GetXPVitality(), player->GetTSXP(), player->GetNeededTSXP(), player->GetTSXPVitality(), player->GetBankCoinsCopper(),
|
||||
player->GetBankCoinsSilver(), player->GetBankCoinsGold(), player->GetBankCoinsPlat(), client->GetPlayer()->GetPlayerInfo()->GetBindZoneID(), client->GetPlayer()->GetPlayerInfo()->GetBindZoneX(), client->GetPlayer()->GetPlayerInfo()->GetBindZoneY(), client->GetPlayer()->GetPlayerInfo()->GetBindZoneZ(), client->GetPlayer()->GetPlayerInfo()->GetBindZoneHeading(), client->GetPlayer()->GetPlayerInfo()->GetHouseZoneID(),
|
||||
|
@ -7169,3 +7275,49 @@ void WorldDatabase::LoadStartingSpells(World* world)
|
|||
|
||||
world->MStartingLists.releasewritelock();
|
||||
}
|
||||
|
||||
|
||||
bool WorldDatabase::DeleteSpiritShard(int32 id){
|
||||
Query query;
|
||||
query.RunQuery2(Q_DELETE, "delete FROM character_spirit_shards where id=%u",id);
|
||||
if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF){
|
||||
LogWrite(WORLD__ERROR, 0, "World", "Error in DeleteSpiritShard query '%s': %s", query.GetQuery(), query.GetError());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int32 WorldDatabase::CreateSpiritShard(const char* name, int32 level, int8 race, int8 gender, int8 adventure_class,
|
||||
int16 model_type, int16 soga_model_type, int16 hair_type, int16 hair_face_type, int16 wing_type,
|
||||
int16 chest_type, int16 legs_type, int16 soga_hair_type, int16 soga_hair_face_type, int8 hide_hood,
|
||||
int16 size, int16 collision_radius, int16 action_state, int16 visual_state, int16 mood_state, int16 emote_state,
|
||||
int16 pos_state, int16 activity_status, char* sub_title, char* prefix_title, char* suffix_title, char* lastname,
|
||||
float x, float y, float z, float heading, int32 gridid, int32 charid, int32 zoneid, int32 instanceid)
|
||||
{
|
||||
LogWrite(WORLD__INFO, 3, "World", "Saving Spirit Shard %s %u", name, charid);
|
||||
|
||||
Query query;
|
||||
char* name_escaped = getEscapeString(name);
|
||||
|
||||
if(!sub_title)
|
||||
sub_title = "";
|
||||
char* subtitle_escaped = getEscapeString(sub_title);
|
||||
char* prefix_escaped = getEscapeString(prefix_title);
|
||||
char* suffix_escaped = getEscapeString(suffix_title);
|
||||
char* lastname_escaped = getEscapeString(lastname);
|
||||
string insert = string("INSERT INTO character_spirit_shards (name, level, race, gender, adventure_class, model_type, soga_model_type, hair_type, hair_face_type, wing_type, chest_type, legs_type, soga_hair_type, soga_hair_face_type, hide_hood, size, collision_radius, action_state, visual_state, mood_state, emote_state, pos_state, activity_status, sub_title, prefix_title, suffix_title, lastname, x, y, z, heading, gridid, charid, zoneid, instanceid) VALUES ('%s', %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, '%s', '%s', '%s', '%s', %f, %f, %f, %f, %u, %u, %u, %u)");
|
||||
query.RunQuery2(Q_INSERT, insert.c_str(), name_escaped, level, race, gender, adventure_class, model_type, soga_model_type,
|
||||
hair_type, hair_face_type, wing_type, chest_type, legs_type, soga_hair_type,
|
||||
soga_hair_face_type, hide_hood, size, collision_radius, action_state, visual_state,
|
||||
mood_state, emote_state, pos_state, activity_status, subtitle_escaped, prefix_escaped, suffix_escaped,
|
||||
lastname_escaped, x, y, z, heading, gridid, charid, zoneid, instanceid);
|
||||
|
||||
|
||||
safe_delete_array(name_escaped);
|
||||
safe_delete_array(subtitle_escaped);
|
||||
safe_delete_array(prefix_escaped);
|
||||
safe_delete_array(suffix_escaped);
|
||||
safe_delete_array(lastname_escaped);
|
||||
|
||||
return query.GetLastInsertedID();
|
||||
}
|
|
@ -245,6 +245,7 @@ public:
|
|||
void LoadSpawns(ZoneServer* zone);
|
||||
int8 GetAppearanceType(string type);
|
||||
void LoadNPCs(ZoneServer* zone);
|
||||
void LoadSpiritShards(ZoneServer* zone);
|
||||
int32 LoadAppearances(ZoneServer* zone, Client* client = 0);
|
||||
int32 LoadNPCSpells(ZoneServer* zone);
|
||||
int32 LoadNPCSkills(ZoneServer* zone);
|
||||
|
@ -594,6 +595,14 @@ public:
|
|||
|
||||
void LoadStartingSkills(World* world);
|
||||
void LoadStartingSpells(World* world);
|
||||
|
||||
int32 CreateSpiritShard(const char* name, int32 level, int8 race, int8 gender, int8 adventure_class,
|
||||
int16 model_type, int16 soga_model_type, int16 hair_type, int16 hair_face_type, int16 wing_type,
|
||||
int16 chest_type, int16 legs_type, int16 soga_hair_type, int16 soga_hair_face_type, int8 hide_hood,
|
||||
int16 size, int16 collision_radius, int16 action_state, int16 visual_state, int16 mood_state, int16 emote_state,
|
||||
int16 pos_state, int16 activity_status, char* sub_title, char* prefix_title, char* suffix_title, char* lastname,
|
||||
float x, float y, float z, float heading, int32 gridid, int32 charid, int32 zoneid, int32 instanceid);
|
||||
bool DeleteSpiritShard(int32 id);
|
||||
private:
|
||||
DatabaseNew database_new;
|
||||
map<int32, string> zone_names;
|
||||
|
|
|
@ -199,6 +199,7 @@ Client::Client(EQStream* ieqs) : pos_update(125), quest_pos_timer(2000), lua_deb
|
|||
lastRegionRemapTime = 0;
|
||||
regionDebugMessaging = false;
|
||||
client_reloading_zone = false;
|
||||
last_saved_timestamp = 0;
|
||||
}
|
||||
|
||||
Client::~Client() {
|
||||
|
@ -505,6 +506,14 @@ void Client::HandlePlayerRevive(int32 point_id)
|
|||
QueuePacket(packet->serialize());
|
||||
safe_delete(packet);
|
||||
}
|
||||
float origX, origY, origZ, origHeading = 0.0f;
|
||||
|
||||
origX = player->GetX();
|
||||
origY = player->GetY();
|
||||
origZ = player->GetZ();
|
||||
origHeading = player->GetHeading();
|
||||
ZoneServer* originalZone = GetCurrentZone();
|
||||
int32 origGridID = GetPlayer()->appearance.pos.grid_id;
|
||||
|
||||
float x, y, z, heading;
|
||||
RevivePoint* revive_point = 0;
|
||||
|
@ -621,8 +630,21 @@ void Client::HandlePlayerRevive(int32 point_id)
|
|||
QueuePacket(packet->serialize());
|
||||
safe_delete(packet);
|
||||
}
|
||||
|
||||
if(rule_manager.GetGlobalRule(R_Combat, EnableSpiritShards)->GetBool())
|
||||
{
|
||||
NPC* shard = player->InstantiateSpiritShard(origX, origY, origZ, origHeading, origGridID, originalZone);
|
||||
|
||||
GetCurrentZone()->RemoveSpawn(player, false);
|
||||
if(shard->GetSpawnScript() && strlen(shard->GetSpawnScript()) > 0)
|
||||
originalZone->CallSpawnScript(shard, SPAWN_SCRIPT_PRESPAWN);
|
||||
|
||||
originalZone->RemoveSpawn(player, false);
|
||||
|
||||
originalZone->AddSpawn(shard);
|
||||
|
||||
if(shard->GetSpawnScript() && strlen(shard->GetSpawnScript()) > 0)
|
||||
originalZone->CallSpawnScript(shard, SPAWN_SCRIPT_SPAWN);
|
||||
}
|
||||
|
||||
m_resurrect.writelock(__FUNCTION__, __LINE__);
|
||||
if (current_rez.active)
|
||||
|
@ -3987,6 +4009,7 @@ void Client::Save() {
|
|||
|
||||
UpdateCharacterInstances();
|
||||
|
||||
this->SetLastSavedTimeStamp(Timer::GetCurrentTime2());
|
||||
database.Save(this);
|
||||
if (GetPlayer()->UpdateQuickbarNeeded()) {
|
||||
database.SaveQuickBar(GetCharacterID(), GetPlayer()->GetQuickbar());
|
||||
|
@ -9249,6 +9272,7 @@ bool Client::HandleNewLogin(int32 account_id, int32 access_code)
|
|||
firstlogin = zar->isFirstLogin();
|
||||
LogWrite(ZONE__INFO, 0, "ZoneAuth", "Access Key: %u, Character Name: %s, Account ID: %u, Client Data Version: %u", zar->GetAccessKey(), zar->GetCharacterName(), zar->GetAccountID(), version);
|
||||
if (database.loadCharacter(zar->GetCharacterName(), zar->GetAccountID(), this)) {
|
||||
GetPlayer()->CalculateOfflineDebtRecovery(GetLastSavedTimeStamp());
|
||||
GetPlayer()->vis_changed = false;
|
||||
GetPlayer()->info_changed = false;
|
||||
|
||||
|
|
|
@ -765,7 +765,12 @@ void ZoneServer::ProcessDepop(bool respawns_allowed, bool repop) {
|
|||
DeleteData(false);
|
||||
|
||||
if(repop)
|
||||
{
|
||||
// reload spirit shards for the current zone
|
||||
database.LoadSpiritShards(this);
|
||||
|
||||
LoadingData = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ZoneServer::Depop(bool respawns, bool repop) {
|
||||
|
@ -1244,6 +1249,10 @@ bool ZoneServer::Process()
|
|||
if (reloading) {
|
||||
LogWrite(COMMAND__DEBUG, 0, "Command", "-Loading Entity Commands...");
|
||||
database.LoadEntityCommands(this);
|
||||
LogWrite(NPC__INFO, 0, "NPC", "-Loading Spirit Shard data...");
|
||||
database.LoadSpiritShards(this);
|
||||
LogWrite(NPC__INFO, 0, "NPC", "-Load Spirit Shard data complete!");
|
||||
|
||||
LogWrite(NPC__INFO, 0, "NPC", "-Loading NPC data...");
|
||||
database.LoadNPCs(this);
|
||||
LogWrite(NPC__INFO, 0, "NPC", "-Load NPC data complete!");
|
||||
|
@ -4195,6 +4204,8 @@ void ZoneServer::KillSpawn(bool spawnListLocked, Spawn* dead, Spawn* killer, boo
|
|||
((Player*)dead)->UpdatePlayerStatistic(STAT_PLAYER_TOTAL_DEATHS, 1);
|
||||
client = GetClientBySpawn(dead);
|
||||
|
||||
((Entity*)dead)->HandleDeathExperienceDebt(killer);
|
||||
|
||||
if(client) {
|
||||
|
||||
if(client->GetPlayer()->DamageEquippedItems(10, client))
|
||||
|
|
40
server/SpawnScripts/Generic/SpiritShard.lua
Normal file
40
server/SpawnScripts/Generic/SpiritShard.lua
Normal file
|
@ -0,0 +1,40 @@
|
|||
--[[
|
||||
Script Name : SpawnScripts/Generic/SpiritShard.lua
|
||||
Script Purpose : Spirit Shard
|
||||
--]]
|
||||
|
||||
function spawn(NPC)
|
||||
local DebtToRemovePct = GetRuleFlagFloat("R_Combat", "ShardDebtRecoveryPercent")
|
||||
|
||||
if GetRuleFlagFloat("R_Combat", "ShardRecoveryByRadius") == true then
|
||||
SetPlayerProximityFunction(NPC, 10.0, "recovershard")
|
||||
end
|
||||
|
||||
AddPrimaryEntityCommand(nil,NPC,"Recover Spirit Shard",10.0,"recovershard","",0,0,1)
|
||||
|
||||
local charID = GetShardCharID(NPC)
|
||||
SetAccessToEntityCommandByCharID(NPC, charID, "recovershard", true)
|
||||
end
|
||||
|
||||
function recovershard(NPC, Spawn)
|
||||
local charid = GetShardCharID(NPC)
|
||||
|
||||
if GetCharacterID(Spawn) == charid then
|
||||
local DebtToRemovePct = GetRuleFlagFloat("R_Combat", "ShardDebtRecoveryPercent")
|
||||
local DeathXPDebt = GetRuleFlagFloat("R_Combat", "DeathExperienceDebt")
|
||||
|
||||
local debt = GetInfoStructFloat(Spawn, "xp_debt")
|
||||
local DebtToRemove = (DebtToRemovePct/100.0)*(DeathXPDebt/100.0);
|
||||
if debt > DebtToRemove then
|
||||
SetInfoStructFloat(Spawn, "xp_debt", debt - DebtToRemove)
|
||||
else
|
||||
SetInfoStructFloat(Spawn, "xp_debt", 0.0)
|
||||
end
|
||||
|
||||
SendMessage(Spawn, "You recover a spirit shard and recovered some experience debt.", "white")
|
||||
SetCharSheetChanged(Spawn, true)
|
||||
local shardid = GetShardID(NPC)
|
||||
DeleteDBShardID(shardid)
|
||||
Despawn(NPC)
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue