diff --git a/zone/client.cpp b/zone/client.cpp index 2fa49b6af..6ecc3031b 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -354,10 +354,6 @@ Client::~Client() { client_logs.unsubscribeAll(this); #endif - -// if(AbilityTimer || GetLevel()>=51) -// database.UpdateAndDeleteAATimers(CharacterID()); - ChangeSQLLog(nullptr); if(IsDueling() && GetDuelTarget() != 0) { Entity* entity = entity_list.GetID(GetDuelTarget()); diff --git a/zone/embparser.cpp b/zone/embparser.cpp index 9b595d6b1..0cca50623 100644 --- a/zone/embparser.cpp +++ b/zone/embparser.cpp @@ -107,7 +107,9 @@ const char *QuestEventSubroutines[_LargestEventID] = { "EVENT_AUGMENT_ITEM", "EVENT_UNAUGMENT_ITEM", "EVENT_AUGMENT_INSERT", - "EVENT_AUGMENT_REMOVE" + "EVENT_AUGMENT_REMOVE", + "EVENT_ENTER_AREA", + "EVENT_LEAVE_AREA" }; PerlembParser::PerlembParser() : perl(nullptr), event_queue_in_use_(false) { diff --git a/zone/entity.cpp b/zone/entity.cpp index b5aa20c66..41d2985f7 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -3204,7 +3204,7 @@ void EntityList::ClearFeignAggro(Mob* targ) if(targ->IsClient()) { std::vector args; args.push_back(iterator.GetData()); - int i = parse->EventPlayer(EVENT_FEIGN_DEATH, targ->CastToClient(), "", 0); + int i = parse->EventPlayer(EVENT_FEIGN_DEATH, targ->CastToClient(), "", 0, &args); if(i != 0) { iterator.Advance(); continue; @@ -3545,80 +3545,62 @@ void EntityList::RemoveAllLocalities() { proximity_list.clear(); } -void EntityList::ProcessMove(Client *c, float x, float y, float z) { - /* - We look through each proximity, looking to see if last_* was in(out) - the proximity, and the new supplied coords are out(in)... - */ - std::list skip_ids; +struct quest_proximity_event { + QuestEventID event_id; + Client *client; + NPC *npc; + int area_id; + int area_type; +}; +void EntityList::ProcessMove(Client *c, float x, float y, float z) { float last_x = c->ProximityX(); float last_y = c->ProximityY(); float last_z = c->ProximityZ(); - auto iter = proximity_list.begin(); - for(; iter != proximity_list.end(); ++iter) { + std::list events; + for(auto iter = proximity_list.begin(); iter != proximity_list.end(); ++iter) { NPC *d = (*iter); NPCProximity *l = d->proximity; if(l == nullptr) continue; - - //This is done to address the issue of this code not being reentrant - //because perl can call clear_proximity() while we're still iterating through the list - //This causes our list to become invalid but we don't know it. On GCC it's basic heap - //corruption and it doesn't appear to catch it at all. - //MSVC it's a crash with 0xfeeefeee debug address (freed memory off the heap) - std::list::iterator skip_iter = skip_ids.begin(); - bool skip = false; - while(skip_iter != skip_ids.end()) - { - if(d->GetID() == (*skip_iter)) - { - skip = true; - break; - } - ++skip_iter; - } - - if(skip) - { - continue; - } - + //check both bounding boxes, if either coords pairs //cross a boundary, send the event. bool old_in = true; bool new_in = true; - if(last_x < l->min_x || last_x > l->max_x - || last_y < l->min_y || last_y > l->max_y - || last_z < l->min_z || last_z > l->max_z ) { + if(last_x < l->min_x || last_x > l->max_x || + last_y < l->min_y || last_y > l->max_y || + last_z < l->min_z || last_z > l->max_z ) { old_in = false; } - if(x < l->min_x || x > l->max_x - || y < l->min_y || y > l->max_y - || z < l->min_z || z > l->max_z ) { + if(x < l->min_x || x > l->max_x || + y < l->min_y || y > l->max_y || + z < l->min_z || z > l->max_z ) { new_in = false; } - + if(old_in && !new_in) { - //we were in the proximity, we are no longer, send event exit - parse->EventNPC(EVENT_EXIT, d, c, "", 0); - - //Reentrant fix - iter = proximity_list.begin(); - skip_ids.push_back(d->GetID()); + quest_proximity_event evt; + evt.event_id = EVENT_EXIT; + evt.client = c; + evt.npc = d; + evt.area_id = 0; + evt.area_type = 0; + events.push_back(evt); } else if(new_in && !old_in) { - //we were not in the proximity, we are now, send enter event - parse->EventNPC(EVENT_ENTER, d, c, "", 0); - - //Reentrant fix - iter = proximity_list.begin(); - skip_ids.push_back(d->GetID()); + quest_proximity_event evt; + evt.event_id = EVENT_ENTER; + evt.client = c; + evt.npc = d; + evt.area_id = 0; + evt.area_type = 0; + events.push_back(evt); } } - - for(auto area_iter = area_list.begin(); area_iter != area_list.end(); ++area_iter) { - Area& a = (*area_iter); + + for(auto iter = area_list.begin(); iter != area_list.end(); ++iter) { + Area& a = (*iter); bool old_in = true; bool new_in = true; if(last_x < a.min_x || last_x > a.max_x || @@ -3634,11 +3616,37 @@ void EntityList::ProcessMove(Client *c, float x, float y, float z) { { new_in = false; } - + if(old_in && !new_in) { //were in but are no longer. + quest_proximity_event evt; + evt.event_id = EVENT_LEAVE_AREA; + evt.client = c; + evt.npc = nullptr; + evt.area_id = a.id; + evt.area_type = a.type; + events.push_back(evt); } else if (!old_in && new_in) { //were not in but now are + quest_proximity_event evt; + evt.event_id = EVENT_ENTER_AREA; + evt.client = c; + evt.npc = nullptr; + evt.area_id = a.id; + evt.area_type = a.type; + events.push_back(evt); + } + } + + for(auto iter = events.begin(); iter != events.end(); ++iter) { + quest_proximity_event& evt = (*iter); + if(evt.npc) { + parse->EventNPC(evt.event_id, evt.npc, evt.client, "", 0); + } else { + std::vector args; + args.push_back(&evt.area_id); + args.push_back(&evt.area_type); + parse->EventPlayer(evt.event_id, evt.client, "", 0, &args); } } } @@ -3647,9 +3655,10 @@ void EntityList::ProcessMove(NPC *n, float x, float y, float z) { float last_x = n->GetX(); float last_y = n->GetY(); float last_z = n->GetZ(); - - for(auto area_iter = area_list.begin(); area_iter != area_list.end(); ++area_iter) { - Area& a = (*area_iter); + + std::list events; + for(auto iter = area_list.begin(); iter != area_list.end(); ++iter) { + Area& a = (*iter); bool old_in = true; bool new_in = true; if(last_x < a.min_x || last_x > a.max_x || @@ -3665,13 +3674,35 @@ void EntityList::ProcessMove(NPC *n, float x, float y, float z) { { new_in = false; } - + if(old_in && !new_in) { //were in but are no longer. + quest_proximity_event evt; + evt.event_id = EVENT_LEAVE_AREA; + evt.client = nullptr; + evt.npc = n; + evt.area_id = a.id; + evt.area_type = a.type; + events.push_back(evt); } else if (!old_in && new_in) { //were not in but now are + quest_proximity_event evt; + evt.event_id = EVENT_ENTER_AREA; + evt.client = nullptr; + evt.npc = n; + evt.area_id = a.id; + evt.area_type = a.type; + events.push_back(evt); } } + + for(auto iter = events.begin(); iter != events.end(); ++iter) { + quest_proximity_event& evt = (*iter); + std::vector args; + args.push_back(&evt.area_id); + args.push_back(&evt.area_type); + parse->EventNPC(evt.event_id, evt.npc, evt.client, "", 0, &args); + } } void EntityList::AddArea(int id, int type, float min_x, float max_x, float min_y, float max_y, float min_z, float max_z) { diff --git a/zone/entity.h b/zone/entity.h index 32878876f..997056657 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -188,7 +188,7 @@ public: void BeaconProcess(); void ProcessMove(Client *c, float x, float y, float z); void ProcessMove(NPC *n, float x, float y, float z); - void AddArea(int id, int type, float x1, float x2, float y1, float y2, float z1, float z2); + void AddArea(int id, int type, float min_x, float max_x, float min_y, float max_y, float min_z, float max_z); void RemoveArea(int id); void ClearAreas(); void ProcessProximitySay(const char *Message, Client *c, uint8 language = 0); diff --git a/zone/event_codes.h b/zone/event_codes.h index d916a9635..f8861a097 100644 --- a/zone/event_codes.h +++ b/zone/event_codes.h @@ -76,6 +76,8 @@ typedef enum { EVENT_UNAUGMENT_ITEM, EVENT_AUGMENT_INSERT, EVENT_AUGMENT_REMOVE, + EVENT_ENTER_AREA, + EVENT_LEAVE_AREA, _LargestEventID } QuestEventID; diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index 0562545ba..871b0d825 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -106,28 +106,18 @@ void unregister_player_event(std::string name, int evt) { unregister_event("player", name, evt); } -void register_item_event(std::string name, int evt, Lua_Item item, luabind::object func) { - const Item_Struct *itm = item; - if(!itm) { - return; - } - +void register_item_event(std::string name, int evt, int item_id, luabind::object func) { std::string package_name = "item_"; - package_name += std::to_string(itm->ID); + package_name += std::to_string(item_id); if(luabind::type(func) == LUA_TFUNCTION) { register_event(package_name, name, evt, func); } } -void unregister_item_event(std::string name, int evt, Lua_Item item) { - const Item_Struct *itm = item; - if(!itm) { - return; - } - +void unregister_item_event(std::string name, int evt, int item_id) { std::string package_name = "item_"; - package_name += std::to_string(itm->ID); + package_name += std::to_string(item_id); unregister_event(package_name, name, evt); } @@ -773,6 +763,18 @@ int lua_get_zone_weather() { return zone->zone_weather; } +void lua_add_area(int id, int type, float min_x, float max_x, float min_y, float max_y, float min_z, float max_z) { + entity_list.AddArea(id, type, min_x, max_x, min_y, max_y, min_z, max_z); +} + +void lua_remove_area(int id) { + entity_list.RemoveArea(id); +} + +void lua_clear_areas() { + entity_list.ClearAreas(); +} + luabind::object lua_get_zone_time(lua_State *L) { TimeOfDay_Struct eqTime; zone->zone_time.getEQTimeOfDay(time(0), &eqTime); @@ -927,7 +929,10 @@ luabind::scope lua_register_general() { luabind::def("get_zone_instance_id", &lua_get_zone_instance_id), luabind::def("get_zone_instance_version", &lua_get_zone_instance_version), luabind::def("get_zone_weather", &lua_get_zone_weather), - luabind::def("get_zone_time", &lua_get_zone_time) + luabind::def("get_zone_time", &lua_get_zone_time), + luabind::def("add_area", &lua_add_area), + luabind::def("remove_area", &lua_remove_area), + luabind::def("clear_areas", &lua_clear_areas) ]; } @@ -997,7 +1002,15 @@ luabind::scope lua_register_events() { luabind::value("drop_item", static_cast(EVENT_DROP_ITEM)), luabind::value("destroy_item", static_cast(EVENT_DESTROY_ITEM)), luabind::value("feign_death", static_cast(EVENT_FEIGN_DEATH)), - luabind::value("weapon_proc", static_cast(EVENT_WEAPON_PROC)) + luabind::value("weapon_proc", static_cast(EVENT_WEAPON_PROC)), + luabind::value("equip_item", static_cast(EVENT_EQUIP_ITEM)), + luabind::value("unequip_item", static_cast(EVENT_UNEQUIP_ITEM)), + luabind::value("augment_item", static_cast(EVENT_AUGMENT_ITEM)), + luabind::value("unaugment_item", static_cast(EVENT_UNAUGMENT_ITEM)), + luabind::value("augment_insert", static_cast(EVENT_AUGMENT_INSERT)), + luabind::value("augment_remove", static_cast(EVENT_AUGMENT_REMOVE)), + luabind::value("enter_area", static_cast(EVENT_ENTER_AREA)), + luabind::value("leave_area", static_cast(EVENT_LEAVE_AREA)) ]; } diff --git a/zone/lua_parser.cpp b/zone/lua_parser.cpp index 87f00c645..1419d38d3 100644 --- a/zone/lua_parser.cpp +++ b/zone/lua_parser.cpp @@ -106,7 +106,9 @@ const char *LuaEvents[_LargestEventID] = { "event_augment_item", "event_unaugment_item", "event_augment_insert", - "event_augment_remove" + "event_augment_remove", + "event_enter_area", + "event_leave_area" }; extern Zone *zone; @@ -150,6 +152,8 @@ LuaParser::LuaParser() { NPCArgumentDispatch[EVENT_CAST] = handle_npc_cast; NPCArgumentDispatch[EVENT_CAST_BEGIN] = handle_npc_cast; NPCArgumentDispatch[EVENT_FEIGN_DEATH] = handle_npc_single_client; + NPCArgumentDispatch[EVENT_ENTER_AREA] = handle_npc_area; + NPCArgumentDispatch[EVENT_LEAVE_AREA] = handle_npc_area; PlayerArgumentDispatch[EVENT_SAY] = handle_player_say; PlayerArgumentDispatch[EVENT_DEATH] = handle_player_death; @@ -176,6 +180,8 @@ LuaParser::LuaParser() { PlayerArgumentDispatch[EVENT_COMBINE_SUCCESS] = handle_player_combine; PlayerArgumentDispatch[EVENT_COMBINE_FAILURE] = handle_player_combine; PlayerArgumentDispatch[EVENT_FEIGN_DEATH] = handle_player_feign; + PlayerArgumentDispatch[EVENT_ENTER_AREA] = handle_player_area; + PlayerArgumentDispatch[EVENT_LEAVE_AREA] = handle_player_area; ItemArgumentDispatch[EVENT_ITEM_CLICK] = handle_item_click; ItemArgumentDispatch[EVENT_ITEM_CLICK_CAST] = handle_item_click; diff --git a/zone/lua_parser_events.cpp b/zone/lua_parser_events.cpp index b19c0234d..922cccdeb 100644 --- a/zone/lua_parser_events.cpp +++ b/zone/lua_parser_events.cpp @@ -218,6 +218,15 @@ void handle_npc_cast(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, s } } +void handle_npc_area(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, + std::vector *extra_pointers) { + lua_pushinteger(L, *reinterpret_cast(extra_pointers->at(0))); + lua_setfield(L, -2, "area_id"); + + lua_pushinteger(L, *reinterpret_cast(extra_pointers->at(1))); + lua_setfield(L, -2, "area_type"); +} + void handle_npc_null(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers) { } @@ -438,6 +447,19 @@ void handle_player_combine(QuestInterface *parse, lua_State* L, Client* client, void handle_player_feign(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector *extra_pointers) { + Lua_NPC l_npc(reinterpret_cast(extra_pointers->at(0))); + luabind::object l_npc_o = luabind::object(L, l_npc); + l_npc_o.push(L); + lua_setfield(L, -2, "other"); +} + +void handle_player_area(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, + std::vector *extra_pointers) { + lua_pushinteger(L, *reinterpret_cast(extra_pointers->at(0))); + lua_setfield(L, -2, "area_id"); + + lua_pushinteger(L, *reinterpret_cast(extra_pointers->at(1))); + lua_setfield(L, -2, "area_type"); } void handle_player_null(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, diff --git a/zone/lua_parser_events.h b/zone/lua_parser_events.h index 50e3f927c..9f5c10335 100644 --- a/zone/lua_parser_events.h +++ b/zone/lua_parser_events.h @@ -36,6 +36,8 @@ void handle_npc_death(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::vector *extra_pointers); void handle_npc_cast(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers); +void handle_npc_area(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, + std::vector *extra_pointers); void handle_npc_null(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers); @@ -82,6 +84,8 @@ void handle_player_combine(QuestInterface *parse, lua_State* L, Client* client, std::vector *extra_pointers); void handle_player_feign(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector *extra_pointers); +void handle_player_area(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, + std::vector *extra_pointers); void handle_player_null(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector *extra_pointers); diff --git a/zone/mob.cpp b/zone/mob.cpp index 941d14360..3acd05619 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -1355,6 +1355,10 @@ void Mob::GMMove(float x, float y, float z, float heading, bool SendUpdate) { Route.clear(); + if(IsNPC()) { + entity_list.ProcessMove(CastToNPC(), x, y, z); + } + x_pos = x; y_pos = y; z_pos = z; @@ -2692,6 +2696,10 @@ void Mob::SetNextIncHPEvent( int inchpevent ) //warp for quest function,from sandy void Mob::Warp( float x, float y, float z ) { + if(IsNPC()) { + entity_list.ProcessMove(CastToNPC(), x, y, z); + } + x_pos = x; y_pos = y; z_pos = z; diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index 5675c16c1..c00d629f8 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -534,6 +534,11 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b else if ((ABS(x_pos - x) < 0.1) && (ABS(y_pos - y) < 0.1)) { mlog(AI__WAYPOINTS, "Calc Position2 (%.3f, %.3f, %.3f): X/Y difference <0.1, Jumping to target.", x, y, z); + + if(IsNPC()) { + entity_list.ProcessMove(CastToNPC(), x, y, z); + } + x_pos = x; y_pos = y; z_pos = z; @@ -541,10 +546,18 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b } int compare_steps = IsBoat() ? 1 : 20; - if(tar_ndx < compare_steps && tarx==x && tary==y){ - x_pos = x_pos + tar_vx*tar_vector; - y_pos = y_pos + tar_vy*tar_vector; - z_pos = z_pos + tar_vz*tar_vector; + if(tar_ndx < compare_steps && tarx==x && tary==y) { + + float new_x = x_pos + tar_vx*tar_vector; + float new_y = y_pos + tar_vy*tar_vector; + float new_z = z_pos + tar_vz*tar_vector; + if(IsNPC()) { + entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z); + } + + x_pos = new_x; + y_pos = new_y; + z_pos = new_z; mlog(AI__WAYPOINTS, "Calculating new position2 to (%.3f, %.3f, %.3f), old vector (%.3f, %.3f, %.3f)", x, y, z, tar_vx, tar_vy, tar_vz); @@ -630,15 +643,27 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b tar_vx = tar_vx/numsteps; tar_vy = tar_vy/numsteps; tar_vz = tar_vz/numsteps; - x_pos = x_pos + tar_vx; - y_pos = y_pos + tar_vy; - z_pos = z_pos + tar_vz; + + float new_x = x_pos + tar_vx; + float new_y = y_pos + tar_vy; + float new_z = z_pos + tar_vz; + if(IsNPC()) { + entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z); + } + + x_pos = new_x; + y_pos = new_y; + z_pos = new_z; tar_ndx=22-numsteps; heading = CalculateHeadingToTarget(x, y); mlog(AI__WAYPOINTS, "Next position2 (%.3f, %.3f, %.3f) (%d steps)", x_pos, y_pos, z_pos, numsteps); } else { + if(IsNPC()) { + entity_list.ProcessMove(CastToNPC(), x, y, z); + } + x_pos = x; y_pos = y; z_pos = z; @@ -650,9 +675,17 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b else { tar_vector/=20; - x_pos = x_pos + tar_vx*tar_vector; - y_pos = y_pos + tar_vy*tar_vector; - z_pos = z_pos + tar_vz*tar_vector; + + float new_x = x_pos + tar_vx*tar_vector; + float new_y = y_pos + tar_vy*tar_vector; + float new_z = z_pos + tar_vz*tar_vector; + if(IsNPC()) { + entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z); + } + + x_pos = new_x; + y_pos = new_y; + z_pos = new_z; heading = CalculateHeadingToTarget(x, y); mlog(AI__WAYPOINTS, "Next position2 (%.3f, %.3f, %.3f) (%d steps)", x_pos, y_pos, z_pos, numsteps); } @@ -762,15 +795,26 @@ bool Mob::CalculateNewPosition(float x, float y, float z, float speed, bool chec heading = CalculateHeadingToTarget(x, y); if (tar_vector >= 1.0) { + if(IsNPC()) { + entity_list.ProcessMove(CastToNPC(), x, y, z); + } + x_pos = x; y_pos = y; z_pos = z; mlog(AI__WAYPOINTS, "Close enough, jumping to waypoint"); } else { - x_pos = x_pos + tar_vx*tar_vector; - y_pos = y_pos + tar_vy*tar_vector; - z_pos = z_pos + tar_vz*tar_vector; + float new_x = x_pos + tar_vx*tar_vector; + float new_y = y_pos + tar_vy*tar_vector; + float new_z = z_pos + tar_vz*tar_vector; + if(IsNPC()) { + entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z); + } + + x_pos = new_x; + y_pos = new_y; + z_pos = new_z; mlog(AI__WAYPOINTS, "Next position (%.3f, %.3f, %.3f)", x_pos, y_pos, z_pos); } @@ -933,6 +977,10 @@ void NPC::AssignWaypoints(int32 grid) { } void Mob::SendTo(float new_x, float new_y, float new_z) { + if(IsNPC()) { + entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z); + } + x_pos = new_x; y_pos = new_y; z_pos = new_z; @@ -963,6 +1011,10 @@ void Mob::SendTo(float new_x, float new_y, float new_z) { } void Mob::SendToFixZ(float new_x, float new_y, float new_z) { + if(IsNPC()) { + entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z + 0.1); + } + x_pos = new_x; y_pos = new_y; z_pos = new_z + 0.1;