Loading...   


 zone/entity.cpp        |  9 ++++-
 zone/lua_mob.cpp       | 18 ++++++++++
 zone/lua_mob.h         |  3 ++
 zone/mob.cpp           | 63 ++++++++++++++++++++++++++++++++++
 zone/mob.h             |  8 +++++
 zone/mod_functions.cpp |  7 +++-
 zone/perl_mob.cpp      | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++
 zone/questmgr.cpp      |  1 +
 8 files changed, 199 insertions(+), 2 deletions(-)

diff --git a/zone/entity.cpp b/zone/entity.cpp
index a79d016..732d3f5 100644
--- a/zone/entity.cpp
+++ b/zone/entity.cpp
@@ -648,7 +648,7 @@ void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue)
 	if (emoteid != 0)
 		npc->DoNPCEmote(ONSPAWN, emoteid);
 
-	if (SendSpawnPacket) {
+	if (SendSpawnPacket && !npc->GetQuestHide()) {
 		if (dontqueue) { // aka, SEND IT NOW BITCH!
 			EQApplicationPacket *app = new EQApplicationPacket;
 			npc->CreateSpawnPacket(app, npc);
@@ -1207,6 +1207,10 @@ void EntityList::SendZoneSpawns(Client *client)
 				++it;
 				continue;
 			}
+			if (ent->QuestHidden(client)) {
+				++it;
+				continue;
+			}
 		}
 
 		app = new EQApplicationPacket;
@@ -1235,6 +1239,9 @@ void EntityList::SendZoneSpawnsBulk(Client *client)
 			if (spawn->IsClient() && (spawn->CastToClient()->GMHideMe(client) ||
 					spawn->CastToClient()->IsHoveringForRespawn()))
 				continue;
+				
+			if (spawn->QuestHidden(client))
+				continue;
 
 			race = spawn->GetRace();
 
diff --git a/zone/lua_mob.cpp b/zone/lua_mob.cpp
index 38fd80c..57214f6 100644
--- a/zone/lua_mob.cpp
+++ b/zone/lua_mob.cpp
@@ -18,6 +18,21 @@ const char *Lua_Mob::GetName() {
 	return self->GetName();
 }
 
+void Lua_Mob::SetQuestHide(bool flag) {
+	Lua_Safe_Call_Void();
+	self->SetQuestHide(flag);
+}
+
+void Lua_Mob::RevealTo(Lua_Client client) {
+	Lua_Safe_Call_Void();
+	self->RevealTo(client);
+}
+
+void Lua_Mob::HideFrom(Lua_Client client) {
+	Lua_Safe_Call_Void();
+	self->HideFrom(client);
+}
+
 void Lua_Mob::Depop() {
 	Lua_Safe_Call_Void();
 	return self->Depop();
@@ -1985,6 +2000,9 @@ luabind::scope lua_register_mob() {
 	return luabind::class_<Lua_Mob, Lua_Entity>("Mob")
 		.def(luabind::constructor<>())
 		.def("GetName", &Lua_Mob::GetName)
+		.def("SetQuestHide", (void(Lua_Mob::*)(bool))&Lua_Mob::SetQuestHide)
+		.def("RevealTo", (void(Lua_Mob::*)(Lua_Client))&Lua_Mob::RevealTo)
+		.def("HideFrom", (void(Lua_Mob::*)(Lua_Client))&Lua_Mob::HideFrom)
 		.def("Depop", (void(Lua_Mob::*)(void))&Lua_Mob::Depop)
 		.def("Depop", (void(Lua_Mob::*)(bool))&Lua_Mob::Depop)
 		.def("BehindMob", (bool(Lua_Mob::*)(void))&Lua_Mob::BehindMob)
diff --git a/zone/lua_mob.h b/zone/lua_mob.h
index cbc34dc..1346520 100644
--- a/zone/lua_mob.h
+++ b/zone/lua_mob.h
@@ -30,6 +30,9 @@ public:
 	}
 
 	const char *GetName();
+	void SetQuestHide(bool flag);
+	void RevealTo(Lua_Client client);
+	void HideFrom(Lua_Client client);
 	void Depop();
 	void Depop(bool start_spawn_timer);
 	bool BehindMob();
diff --git a/zone/mob.cpp b/zone/mob.cpp
index 0e2cd7d..1790a4f 100644
--- a/zone/mob.cpp
+++ b/zone/mob.cpp
@@ -436,6 +436,7 @@ Mob::Mob(const char* in_name,
 	PrimaryAggro = false;
 	AssistAggro = false;
 	npc_assist_cap = 0;
+	questhidden = false;
 }
 
 Mob::~Mob()
@@ -5861,3 +5862,65 @@ int Mob::CheckBaneDamage(const ItemInst *item)
 
 	return damage;
 }
+
+bool Mob::QuestHidden(Client *client) {
+	if (questhidden && client) {
+		std::string ent_var = StringFormat("Reveal_%s", client->GetCleanName());
+		if (GetEntityVariable(ent_var.c_str()) == "1" || client->Admin() >= 250) {
+			return false; //This player can view them...
+		}
+		else {
+			return true; //This player cannot view them..
+		}
+	}
+	else {
+		return false; //This NPC is not questhidden...
+	}
+}
+
+void Mob::SetQuestHide(bool flag)
+{
+	EQApplicationPacket app;
+
+	questhidden = flag;
+	uint8 gm_level = 255;
+
+	if (questhidden)
+	{
+		CreateDespawnPacket(&app, false);
+		entity_list.RemoveFromTargets(this);
+		trackable = false;
+		gm_level = 249; //Hide for everyone except GMs 250+
+	}
+	else
+	{
+		CreateSpawnPacket(&app);
+		trackable = true;
+	}
+
+	entity_list.QueueClientsStatus(this, &app, true, 0, gm_level);
+}
+
+void Mob::RevealTo(Client *client) 
+{
+	if (client != nullptr) {
+		std::string ent_var = StringFormat("Reveal_%s", client->GetCleanName());
+		SetEntityVariable(ent_var.c_str(), "1"); //We see the mob..
+		EQApplicationPacket app;
+		CreateSpawnPacket(&app);
+		client->QueuePacket(&app);
+	}
+
+}
+
+void Mob::HideFrom(Client *client)
+{
+	if (client != nullptr) {
+		std::string ent_var = StringFormat("Reveal_%s", client->GetCleanName());
+		SetEntityVariable(ent_var.c_str(), "0"); //We dont see the mob..
+		EQApplicationPacket app;
+		CreateDespawnPacket(&app, false);
+		client->QueuePacket(&app);
+	}
+
+}
\ No newline at end of file
diff --git a/zone/mob.h b/zone/mob.h
index 5546340..b6240c1 100644
--- a/zone/mob.h
+++ b/zone/mob.h
@@ -128,6 +128,13 @@ public:
 
 	//Somewhat sorted: needs documenting!
 
+	//Custom
+	bool QuestHidden(Client* client = 0);
+	void SetQuestHide(bool flag);
+	bool GetQuestHide(){ return questhidden; }
+	void RevealTo(Client *client);
+	void HideFrom(Client *client);
+
 	//Attack
 	virtual void RogueBackstab(Mob* other, bool min_damage = false, int ReuseTime = 10);
 	virtual void RogueAssassinate(Mob* other);
@@ -1373,6 +1380,7 @@ protected:
 private:
 	void _StopSong(); //this is not what you think it is
 	Mob* target;
+	bool questhidden;
 };
 
 #endif
diff --git a/zone/mod_functions.cpp b/zone/mod_functions.cpp
index 6ae0edd..0930716 100644
--- a/zone/mod_functions.cpp
+++ b/zone/mod_functions.cpp
@@ -23,7 +23,12 @@ void Zone::mod_init() { return; }
 void Zone::mod_repop() { return; }
 
 //Pre-spawn hook called from the NPC object to be spawned
-void NPC::mod_prespawn(Spawn2 *sp) { return; }
+void NPC::mod_prespawn(Spawn2 *sp) { 
+	if (GetCHA() == 1337)
+		SetQuestHide(true);
+	
+	return; 
+}
 
 //Base damage from NPC::Attack
 int NPC::mod_npc_damage(int damage, SkillUseTypes skillinuse, int hand, const Item_Struct* weapon, Mob* other) { return(damage); }
diff --git a/zone/perl_mob.cpp b/zone/perl_mob.cpp
index 8f96849..8649214 100644
--- a/zone/perl_mob.cpp
+++ b/zone/perl_mob.cpp
@@ -44,6 +44,95 @@ typedef const char Const_char;
 #undef THIS
 #endif
 
+XS(XS_Mob_SetQuestHide); /* prototype to pass -Wmissing-prototypes */
+XS(XS_Mob_SetQuestHide)
+{
+	dXSARGS;
+	if (items != 2)
+		Perl_croak(aTHX_ "Usage: Mob::SetQuestHide(THIS, flag)");
+	{
+		Mob *		THIS;
+		bool		flag = (bool)SvTRUE(ST(1));
+
+		if (sv_derived_from(ST(0), "Mob")) {
+			IV tmp = SvIV((SV*)SvRV(ST(0)));
+			THIS = INT2PTR(Mob *,tmp);
+		}
+		else
+			Perl_croak(aTHX_ "THIS is not of type Mob");
+		if(THIS == nullptr)
+			Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
+
+		THIS->SetQuestHide(flag);
+	}
+	XSRETURN_EMPTY;
+}
+
+XS(XS_Mob_RevealTo); /* prototype to pass -Wmissing-prototypes */
+XS(XS_Mob_RevealTo)
+{
+	dXSARGS;
+	if (items != 2)
+		Perl_croak(aTHX_ "Usage: Mob::RevealTo(THIS, client)");
+	{
+		Mob *		THIS;
+		Client*		client = nullptr;
+
+		if (sv_derived_from(ST(0), "Mob")) {
+			IV tmp = SvIV((SV*)SvRV(ST(0)));
+			THIS = INT2PTR(Mob *,tmp);
+		}
+		else
+			Perl_croak(aTHX_ "THIS is not of type Mob");
+		if(THIS == nullptr)
+			Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
+		
+		if (sv_derived_from(ST(1), "Client")) {
+			IV tmp = SvIV((SV*)SvRV(ST(1)));
+			client = INT2PTR(Client *,tmp);
+		}
+		else
+			Perl_croak(aTHX_ "client is not of type Client");
+		if(client == nullptr)
+			Perl_croak(aTHX_ "client is nullptr, avoiding crash.");
+
+		THIS->RevealTo(client);
+	}
+	XSRETURN_EMPTY;
+}
+
+XS(XS_Mob_HideFrom); /* prototype to pass -Wmissing-prototypes */
+XS(XS_Mob_HideFrom)
+{
+	dXSARGS;
+	if (items != 2)
+		Perl_croak(aTHX_ "Usage: Mob::HideFrom(THIS, client)");
+	{
+		Mob *		THIS;
+		Client*		client = nullptr;
+
+		if (sv_derived_from(ST(0), "Mob")) {
+			IV tmp = SvIV((SV*)SvRV(ST(0)));
+			THIS = INT2PTR(Mob *,tmp);
+		}
+		else
+			Perl_croak(aTHX_ "THIS is not of type Mob");
+		if(THIS == nullptr)
+			Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
+		
+		if (sv_derived_from(ST(1), "Client")) {
+			IV tmp = SvIV((SV*)SvRV(ST(1)));
+			client = INT2PTR(Client *,tmp);
+		}
+		else
+			Perl_croak(aTHX_ "client is not of type Client");
+		if(client == nullptr)
+			Perl_croak(aTHX_ "client is nullptr, avoiding crash.");
+
+		THIS->HideFrom(client);
+	}
+	XSRETURN_EMPTY;
+}
 
 XS(XS_Mob_IsClient); /* prototype to pass -Wmissing-prototypes */
 XS(XS_Mob_IsClient)
@@ -9027,6 +9116,9 @@ XS(boot_Mob)
 
 	XS_VERSION_BOOTCHECK ;
 
+		newXSproto(strcpy(buf, "SetQuestHide"), XS_Mob_SetQuestHide, file, "$$");
+		newXSproto(strcpy(buf, "RevealTo"), XS_Mob_RevealTo, file, "$$");
+		newXSproto(strcpy(buf, "HideFrom"), XS_Mob_HideFrom, file, "$$");
 		newXSproto(strcpy(buf, "IsClient"), XS_Mob_IsClient, file, "$");
 		newXSproto(strcpy(buf, "IsNPC"), XS_Mob_IsNPC, file, "$");
 		newXSproto(strcpy(buf, "IsMob"), XS_Mob_IsMob, file, "$");
diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp
index fa8788b..5957b18 100644
--- a/zone/questmgr.cpp
+++ b/zone/questmgr.cpp
@@ -209,6 +209,7 @@ Mob* QuestManager::spawn2(int npc_type, int grid, int unused, const glm::vec4& p
 	{
 		NPC* npc = new NPC(tmp, nullptr, position, FlyMode3);
 		npc->AddLootTable();
+		npc->mod_prespawn(0);
 		entity_list.AddNPC(npc,true,true);
 		if(grid > 0)
 		{

Raw Paste Data