Loading...   


 common/features.h                |  2 ++
 common/ruletypes.h               |  1 +
 zone/embparser.cpp               | 11 ++++++++++-
 zone/entity.cpp                  |  7 +++++++
 zone/event_codes.h               |  3 ++-
 zone/lua_general.cpp             |  4 +++-
 zone/lua_parser.cpp              |  4 +++-
 zone/npc.cpp                     |  7 +++++--
 zone/quest_parser_collection.cpp | 11 +++++++++--
 9 files changed, 42 insertions(+), 8 deletions(-)

diff --git a/common/features.h b/common/features.h
index 2ede4b4..8115efd 100644
--- a/common/features.h
+++ b/common/features.h
@@ -233,6 +233,8 @@ enum {	//some random constants
 #define GROUP_EXP_PER_POINT 1000
 #define RAID_EXP_PER_POINT 2000
 
+#define ZONE_CONTROLLER_NPC_ID 10
+
 //Some hard coded statuses from commands and other places:
 enum {
 	minStatusToBeGM = 40,
diff --git a/common/ruletypes.h b/common/ruletypes.h
index 83ef9af..41e4e22 100644
--- a/common/ruletypes.h
+++ b/common/ruletypes.h
@@ -233,6 +233,7 @@ RULE_BOOL(Zone, LevelBasedEXPMods, false) // Allows you to use the level_exp_mod
 RULE_INT(Zone, WeatherTimer, 600) // Weather timer when no duration is available
 RULE_BOOL(Zone, EnableLoggedOffReplenishments, true)
 RULE_INT(Zone, MinOfflineTimeToReplenishments, 21600) // 21600 seconds is 6 Hours
+RULE_BOOL(Zone, UseZoneController, true) // Enables the ability to use persistent quest based zone controllers (zone_controller.pl/lua)
 RULE_CATEGORY_END()
 
 RULE_CATEGORY(Map)
diff --git a/zone/embparser.cpp b/zone/embparser.cpp
index 617d17d..167bb81 100644
--- a/zone/embparser.cpp
+++ b/zone/embparser.cpp
@@ -114,7 +114,9 @@ const char *QuestEventSubroutines[_LargestEventID] = {
 	"EVENT_RESPAWN",
 	"EVENT_DEATH_COMPLETE",
 	"EVENT_UNHANDLED_OPCODE",
-	"EVENT_TICK"
+	"EVENT_TICK",
+	"EVENT_SPAWN_ZONE",
+	"EVENT_DEATH_ZONE",
 };
 
 PerlembParser::PerlembParser() : perl(nullptr) {
@@ -1424,6 +1426,13 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
 			ExportVar(package_name.c_str(), "slotid", extradata);
 			break;
 		}
+		case EVENT_SPAWN_ZONE: {
+			Seperator sep(data);
+			ExportVar(package_name.c_str(), "spawned_entity_id", sep.arg[0]);
+			ExportVar(package_name.c_str(), "spawned_npc_id", sep.arg[1]);
+			ExportVar(package_name.c_str(), "spawned_npc_name", sep.arg[2]);
+			break;
+		}
 
 		default: {
 			break;
diff --git a/zone/entity.cpp b/zone/entity.cpp
index 23848f7..c075b72 100644
--- a/zone/entity.cpp
+++ b/zone/entity.cpp
@@ -641,8 +641,15 @@ void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue)
 {
 	npc->SetID(GetFreeID());
 	npc->SetMerchantProbability((uint8) zone->random.Int(0, 99));
+
 	parse->EventNPC(EVENT_SPAWN, npc, nullptr, "", 0);
 
+	if (RuleB(Zone, UseZoneController)) {
+		char data_pass[100] = { 0 };
+		snprintf(data_pass, 99, "%d %d %d", npc->GetID(), npc->GetNPCTypeID(), npc->GetCleanName());
+		parse->EventNPC(EVENT_SPAWN_ZONE, entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID), nullptr, data_pass, 0);
+	}
+
 	uint16 emoteid = npc->GetEmoteID();
 	if (emoteid != 0)
 		npc->DoNPCEmote(ONSPAWN, emoteid);
diff --git a/zone/event_codes.h b/zone/event_codes.h
index 7850b0e..1b0e185 100644
--- a/zone/event_codes.h
+++ b/zone/event_codes.h
@@ -83,7 +83,8 @@ typedef enum {
 	EVENT_DEATH_COMPLETE,
 	EVENT_UNHANDLED_OPCODE,
 	EVENT_TICK,
-
+	EVENT_SPAWN_ZONE,
+	EVENT_DEATH_ZONE,
 	_LargestEventID
 } QuestEventID;
 
diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp
index ff0e357..a42efd5 100644
--- a/zone/lua_general.cpp
+++ b/zone/lua_general.cpp
@@ -1731,7 +1731,9 @@ luabind::scope lua_register_events() {
 			luabind::value("leave_area", static_cast<int>(EVENT_LEAVE_AREA)),
 			luabind::value("death_complete", static_cast<int>(EVENT_DEATH_COMPLETE)),
 			luabind::value("unhandled_opcode", static_cast<int>(EVENT_UNHANDLED_OPCODE)),
-			luabind::value("tick", static_cast<int>(EVENT_TICK))
+			luabind::value("tick", static_cast<int>(EVENT_TICK)),
+			luabind::value("spawn_zone", static_cast<int>(EVENT_SPAWN_ZONE)),
+			luabind::value("death_zone", static_cast<int>(EVENT_DEATH_ZONE))
 		];
 }
 
diff --git a/zone/lua_parser.cpp b/zone/lua_parser.cpp
index 4627527..aeb1e32 100644
--- a/zone/lua_parser.cpp
+++ b/zone/lua_parser.cpp
@@ -117,7 +117,9 @@ const char *LuaEvents[_LargestEventID] = {
 	"event_respawn",
 	"event_death_complete",
 	"event_unhandled_opcode",
-	"event_tick"
+	"event_tick",
+	"event_spawn_zone",
+	"event_death_zone"
 };
 
 extern Zone *zone;
diff --git a/zone/npc.cpp b/zone/npc.cpp
index 9d39f4a..2dff845 100644
--- a/zone/npc.cpp
+++ b/zone/npc.cpp
@@ -852,11 +852,11 @@ bool NPC::SpawnZoneController(){
 	npc_type->cur_hp = 2000000000;
 	npc_type->max_hp = 2000000000;
 	npc_type->race = 240;
-	npc_type->gender = 0;
+	npc_type->gender = 2;
 	npc_type->class_ = 1;
 	npc_type->deity = 1;
 	npc_type->level = 200;
-	npc_type->npc_id = 0;
+	npc_type->npc_id = ZONE_CONTROLLER_NPC_ID;
 	npc_type->loottable_id = 0;
 	npc_type->texture = 3;
 	npc_type->runspeed = 0;
@@ -868,6 +868,9 @@ bool NPC::SpawnZoneController(){
 	npc_type->prim_melee_type = 28;
 	npc_type->sec_melee_type = 28;
 
+	npc_type->findable = 0;
+	npc_type->trackable = 0;
+
 	strcpy(npc_type->special_abilities, "12,1^13,1^14,1^15,1^16,1^17,1^19,1^22,1^24,1^25,1^28,1^31,1^35,1^39,1^42,1");
 
 	glm::vec4 point;
diff --git a/zone/quest_parser_collection.cpp b/zone/quest_parser_collection.cpp
index 1f4f99c..e502d37 100644
--- a/zone/quest_parser_collection.cpp
+++ b/zone/quest_parser_collection.cpp
@@ -484,10 +484,17 @@ QuestInterface *QuestParserCollection::GetQIByNPCQuest(uint32 npcid, std::string
 
 	//second look for /quests/zone/npcname.ext (precedence)
 	const NPCType *npc_type = database.LoadNPCTypesData(npcid);
-	if(!npc_type) {
+	if(!npc_type && npcid != 10) {
 		return nullptr;
 	}
-	std::string npc_name = npc_type->name;
+
+	std::string npc_name;
+	if (npcid == ZONE_CONTROLLER_NPC_ID){
+		npc_name = "zone_controller";
+	}
+	else{
+		npc_name = npc_type->name;
+	} 
 	int sz = static_cast<int>(npc_name.length());
 	for(int i = 0; i < sz; ++i) {
 		if(npc_name[i] == '`') {

Raw Paste Data