Added quest areas (only accessable in lua) which work similar to proximities except are not attached to any one npc. Also fixed up the proximity code a bit to comply and got rid of my stupid ass fix for the deleting lists thing

This commit is contained in:
KimLS 2013-06-22 20:47:11 -07:00
parent bb1282de30
commit 0dc66b3dd7
11 changed files with 231 additions and 95 deletions

View File

@ -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());

View File

@ -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) {

View File

@ -3204,7 +3204,7 @@ void EntityList::ClearFeignAggro(Mob* targ)
if(targ->IsClient()) {
std::vector<void*> 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<int> 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<quest_proximity_event> 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<int>::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<void*> 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<quest_proximity_event> 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<void*> 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) {

View File

@ -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);

View File

@ -76,6 +76,8 @@ typedef enum {
EVENT_UNAUGMENT_ITEM,
EVENT_AUGMENT_INSERT,
EVENT_AUGMENT_REMOVE,
EVENT_ENTER_AREA,
EVENT_LEAVE_AREA,
_LargestEventID
} QuestEventID;

View File

@ -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<int>(EVENT_DROP_ITEM)),
luabind::value("destroy_item", static_cast<int>(EVENT_DESTROY_ITEM)),
luabind::value("feign_death", static_cast<int>(EVENT_FEIGN_DEATH)),
luabind::value("weapon_proc", static_cast<int>(EVENT_WEAPON_PROC))
luabind::value("weapon_proc", static_cast<int>(EVENT_WEAPON_PROC)),
luabind::value("equip_item", static_cast<int>(EVENT_EQUIP_ITEM)),
luabind::value("unequip_item", static_cast<int>(EVENT_UNEQUIP_ITEM)),
luabind::value("augment_item", static_cast<int>(EVENT_AUGMENT_ITEM)),
luabind::value("unaugment_item", static_cast<int>(EVENT_UNAUGMENT_ITEM)),
luabind::value("augment_insert", static_cast<int>(EVENT_AUGMENT_INSERT)),
luabind::value("augment_remove", static_cast<int>(EVENT_AUGMENT_REMOVE)),
luabind::value("enter_area", static_cast<int>(EVENT_ENTER_AREA)),
luabind::value("leave_area", static_cast<int>(EVENT_LEAVE_AREA))
];
}

View File

@ -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;

View File

@ -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<void*> *extra_pointers) {
lua_pushinteger(L, *reinterpret_cast<int*>(extra_pointers->at(0)));
lua_setfield(L, -2, "area_id");
lua_pushinteger(L, *reinterpret_cast<int*>(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<void*> *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<void*> *extra_pointers) {
Lua_NPC l_npc(reinterpret_cast<NPC*>(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<void*> *extra_pointers) {
lua_pushinteger(L, *reinterpret_cast<int*>(extra_pointers->at(0)));
lua_setfield(L, -2, "area_id");
lua_pushinteger(L, *reinterpret_cast<int*>(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,

View File

@ -36,6 +36,8 @@ void handle_npc_death(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init,
std::vector<void*> *extra_pointers);
void handle_npc_cast(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers);
void handle_npc_area(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers);
void handle_npc_null(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers);
@ -82,6 +84,8 @@ void handle_player_combine(QuestInterface *parse, lua_State* L, Client* client,
std::vector<void*> *extra_pointers);
void handle_player_feign(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers);
void handle_player_area(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers);
void handle_player_null(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers);

View File

@ -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;

View File

@ -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;