Browse Source

More work for boats, not done yet

Image 3 years ago
parent
commit
096d3d5323

+ 18 - 1
EQ2/source/WorldServer/Items/Items.cpp

@@ -1282,7 +1282,15 @@ bool Item::IsCollectable(){
 
 bool Item::HasSlot(int8 slot, int8 slot2){
 	for(int32 i=0;i<slot_data.size();i++){
-		if(slot_data[i] == slot || slot_data[i] == slot2)
+		if(slot_data[i] == EQ2_LRING_SLOT && (slot == EQ2_RRING_SLOT || slot2 == EQ2_RRING_SLOT))
+			return true;
+		else if(slot_data[i] == EQ2_LWRIST_SLOT && (slot == EQ2_RWRIST_SLOT || slot2 == EQ2_RWRIST_SLOT))
+			return true;
+		else if(slot_data[i] == EQ2_EARS_SLOT_1 && (slot == EQ2_EARS_SLOT_2 || slot2 == EQ2_EARS_SLOT_2))
+			return true;
+		else if(slot_data[i] == EQ2_CHARM_SLOT_1 && (slot == EQ2_CHARM_SLOT_2 || slot2 == EQ2_CHARM_SLOT_2))
+			return true;
+		else if(slot_data[i] == slot || slot_data[i] == slot2)
 			return true;
 	}
 	return false;
@@ -4060,6 +4068,15 @@ int8 EquipmentItemList::GetFreeSlot(Item* tmp, int8 slot_id){
 				MEquipmentItems.unlock();
 				return slot;
 			}
+			else if ( slot == EQ2_LRING_SLOT || slot == EQ2_EARS_SLOT_1 || slot == EQ2_LWRIST_SLOT || slot == EQ2_CHARM_SLOT_1)
+			{
+				Item* rslot = GetItem(slot+1);
+				if(!rslot)
+				{
+					MEquipmentItems.unlock();
+					return slot+1;
+				}
+			}
 		}
 	}
 	MEquipmentItems.unlock();

+ 63 - 0
EQ2/source/WorldServer/LuaFunctions.cpp

@@ -543,6 +543,25 @@ int EQ2Emu_lua_GetSpawnListByRailID(lua_State* state) {
 	return 0;
 }
 
+int EQ2Emu_lua_GetPassengerSpawnList(lua_State* state) {
+	if (!lua_interface)
+		return 0;
+	Spawn* spawn = lua_interface->GetSpawn(state);
+	if (spawn) {
+		vector<Spawn*> spawns = spawn->GetPassengersOnRail();
+		if (spawns.size() > 0) {
+			lua_createtable(state, spawns.size(), 0);
+			int newTable = lua_gettop(state);
+			for (int32 i = 0; i < spawns.size(); i++) {
+				lua_interface->SetSpawnValue(state, spawns.at(i));
+				lua_rawseti(state, newTable, i + 1);
+			}
+			return 1;
+		}
+	}
+	return 0;
+}
+
 int EQ2Emu_lua_GetVariableValue(lua_State* state) {
 	if (!lua_interface)
 		return 0;
@@ -12193,4 +12212,48 @@ int EQ2Emu_lua_GetSpawnByRailID(lua_State* state) {
 		}
 	}
 	return 0;
+}
+
+int EQ2Emu_lua_SetRailID(lua_State* state) {
+	if (!lua_interface)
+		return 0;
+	Spawn* spawn = lua_interface->GetSpawn(state);
+	sint64 rail_id = lua_interface->GetSInt64Value(state, 2);
+
+	lua_interface->ResetFunctionStack(state);
+
+	bool res = false;
+	if(spawn && spawn->IsTransportSpawn())
+	{
+		//printf("Set rail id %i for %s\n",rail_id,spawn->GetName());
+		spawn->SetRailID(rail_id);
+		res = true;
+	}
+	else if (!spawn) {
+		lua_interface->LogError("%s: LUA SetRailID command error: spawn is not valid, does not exist", lua_interface->GetScriptName(state));
+	}
+	else if(!spawn->IsTransportSpawn()) {
+		lua_interface->LogError("%s: LUA SetRailID command error: spawn %s is not a transport spawn, call AddTransportSpawn(NPC) first", lua_interface->GetScriptName(state), spawn->GetName());
+	}
+	lua_interface->SetBooleanValue(state, res);
+	return 1;
+}
+
+int EQ2Emu_lua_IsZoneLoading(lua_State* state) {
+	ZoneServer* zone = lua_interface->GetZone(state);
+
+	if (zone) {
+		lua_interface->SetBooleanValue(state, zone->IsLoading());
+		return 1;
+	}
+	return 0;
+}
+int EQ2Emu_lua_IsRunning(lua_State* state) {
+	Spawn* spawn = lua_interface->GetSpawn(state);
+
+	if (spawn) {
+		lua_interface->SetBooleanValue(state, spawn->IsRunning());
+		return 1;
+	}
+	return 0;
 }

+ 4 - 0
EQ2/source/WorldServer/LuaFunctions.h

@@ -118,6 +118,7 @@ int EQ2Emu_lua_AddSpawnToSpawnList(lua_State* state);
 int EQ2Emu_lua_RemoveSpawnFromSpawnList(lua_State* state);
 int EQ2Emu_lua_GetSpawnListBySpawnID(lua_State* state); 
 int EQ2Emu_lua_GetSpawnListByRailID(lua_State* state); 
+int EQ2Emu_lua_GetPassengerSpawnList(lua_State* state); 
 int EQ2Emu_lua_GetVariableValue(lua_State* state);
 int EQ2Emu_lua_GetCoinMessage(lua_State* state);
 int EQ2Emu_lua_GetSpawnByGroupID(lua_State* state);
@@ -585,4 +586,7 @@ int EQ2Emu_lua_GetArrowColor(lua_State* state);
 int EQ2Emu_lua_GetTSArrowColor(lua_State* state);
 
 int EQ2Emu_lua_GetSpawnByRailID(lua_State* state);
+int EQ2Emu_lua_SetRailID(lua_State* state);
+int EQ2Emu_lua_IsZoneLoading(lua_State* state);
+int EQ2Emu_lua_IsRunning(lua_State* state);
 #endif

+ 4 - 0
EQ2/source/WorldServer/LuaInterface.cpp

@@ -918,6 +918,7 @@ void LuaInterface::RegisterFunctions(lua_State* state) {
 	lua_register(state, "RemoveSpawnFromSpawnList", EQ2Emu_lua_RemoveSpawnFromSpawnList);
 	lua_register(state, "GetSpawnListBySpawnID", EQ2Emu_lua_GetSpawnListBySpawnID);
 	lua_register(state, "GetSpawnListByRailID", EQ2Emu_lua_GetSpawnListByRailID);
+	lua_register(state, "GetPassengerSpawnList", EQ2Emu_lua_GetPassengerSpawnList);
 	lua_register(state, "GetSpawnFromList", EQ2Emu_lua_GetSpawnFromList);
 	lua_register(state, "GetSpawnListSize", EQ2Emu_lua_GetSpawnListSize);	
 	lua_register(state, "SetFactionID", EQ2Emu_lua_SetFactionID);
@@ -1416,6 +1417,9 @@ void LuaInterface::RegisterFunctions(lua_State* state) {
 	lua_register(state, "GetTSArrowColor", EQ2Emu_lua_GetTSArrowColor);
 	
 	lua_register(state, "GetSpawnByRailID", EQ2Emu_lua_GetSpawnByRailID);
+	lua_register(state, "SetRailID", EQ2Emu_lua_SetRailID);
+	lua_register(state, "IsZoneLoading", EQ2Emu_lua_IsZoneLoading);
+	lua_register(state, "IsRunning", EQ2Emu_lua_IsRunning);
 }
 
 void LuaInterface::LogError(const char* error, ...)  {

+ 15 - 0
EQ2/source/WorldServer/Player.cpp

@@ -3542,6 +3542,12 @@ void Player::PrepareIncomingMovementPacket(int32 len, uchar* data, int16 version
 		if (GetBoatSpawn() == 0 && GetZone()) {
 			boat = GetZone()->GetClosestTransportSpawn(GetX(), GetY(), GetZ());
 			SetBoatSpawn(boat);
+			printf("Set boat: %s\n", boat ? boat->GetName() : "notset");
+			if(boat)
+			{
+				boat->AddRailPassenger(GetCharacterID());
+				GetZone()->CallSpawnScript(boat, SPAWN_SCRIPT_BOARD, this);
+			}
 		}
 
 		if (boat || (GetBoatSpawn() && GetZone())) {
@@ -3570,6 +3576,15 @@ void Player::PrepareIncomingMovementPacket(int32 len, uchar* data, int16 version
 	else if(lift_cooldown.Check())
 	{
 		printf("Disable boat\n");
+		if(GetBoatSpawn())
+		{
+			Spawn* boat = GetZone()->GetSpawnByID(GetBoatSpawn());
+			if(boat)
+			{
+				boat->RemoveRailPassenger(GetCharacterID());
+				GetZone()->CallSpawnScript(boat, SPAWN_SCRIPT_EMBARK, this);
+			}
+		}
 		SetBoatSpawn(0);
 	}
 

+ 71 - 13
EQ2/source/WorldServer/Spawn.cpp

@@ -37,6 +37,7 @@
 extern ConfigReader configReader;
 extern RuleManager rule_manager;
 extern World world;
+extern ZoneList zone_list;
 
 Spawn::Spawn(){ 
 	loot_coins = 0;
@@ -2557,7 +2558,7 @@ void Spawn::InitializeInfoPacketData(Player* spawn, PacketStruct* packet) {
 
 		// if this is either a boat or lift let the client be manipulated by the object
 		// doesn't work for DoF client version 546
-		if (this->GetModelType() == 7941 || appearance.icon == 28 || appearance.icon == 12)
+		if (appearance.icon == 28 || appearance.icon == 12 || IsTransportSpawn())
 		{
 			temp_activity_status += ACTIVITY_STATUS_ISTRANSPORT_1188;
 		}
@@ -2569,7 +2570,7 @@ void Spawn::InitializeInfoPacketData(Player* spawn, PacketStruct* packet) {
 			temp_activity_status = 0xFF;
 
 		// this only partially fixes lifts in classic 283 client if you move just as the lift starts to move
-		if (this->GetModelType() == 7941 || appearance.icon == 28 || appearance.icon == 12)
+		if (appearance.icon == 28 || appearance.icon == 12)
 			packet->setDataByName("is_transport", 1);
 
 		if (MeetsSpawnAccessRequirements(spawn))
@@ -2717,7 +2718,7 @@ void Spawn::MoveToLocation(Spawn* spawn, float distance, bool immediate, bool ma
 
 void Spawn::ProcessMovement(bool isSpawnListLocked){
 	CheckProximities();
-
+	
 	if(IsPlayer()){
 		//Check if player is riding a boat, if so update pos (boat's current location + XYZ offsets)
 		Player* player = ((Player*)this);
@@ -2740,7 +2741,7 @@ void Spawn::ProcessMovement(bool isSpawnListLocked){
 		FixZ(true);
 
 		int32 newGrid = GetMap()->GetGrid()->GetGridID(this);
-		if (!IsFlyingCreature() && newGrid != 0 && newGrid != appearance.pos.grid_id)
+		if ((IsTransportSpawn() || !IsFlyingCreature()) && newGrid != 0 && newGrid != appearance.pos.grid_id)
 			SetPos(&(appearance.pos.grid_id), newGrid);
 
 		forceMapCheck = false;
@@ -2850,7 +2851,7 @@ void Spawn::ProcessMovement(bool isSpawnListLocked){
 					}
 					// delay at target location, only need to set 1 location
 					else
-						AddRunningLocation(data->x, data->y, data->z, data->speed, 0, true, true, "", true);
+						AddRunningLocation(data->x, data->y, data->z, data->speed);
 				}
 				movement_start_time = 0;
 				resume_movement = false;
@@ -2878,7 +2879,8 @@ void Spawn::ProcessMovement(bool isSpawnListLocked){
 					data = movement_loop[nextMove];
 					
 					//Go ahead and face the next location
-					FaceTarget(data->x, data->z);
+					if(data)
+						FaceTarget(data->x, data->z);
 				}
 				// If this waypoint has no delay or we have waited the required time (current time >= delay + movement_start_time)
 				else if(data && data->delay == 0 || (data && data->delay > 0 && Timer::GetCurrentTime2() >= (data->delay+movement_start_time))) {
@@ -2944,6 +2946,11 @@ void Spawn::ProcessMovement(bool isSpawnListLocked){
 	
 	if (!movementCase && IsRunning() && !IsPauseMovementTimerActive()) {
 		CalculateRunningLocation();
+		//last_movement_update = Timer::GetCurrentTime2();
+	}
+	else if(movementCase)
+	{
+		//last_movement_update = Timer::GetCurrentTime2();
 	}
 	/*else if (IsNPC() && !IsRunning() && !EngagedInCombat() && ((NPC*)this)->GetRunbackLocation()) {
 		// Is an npc that is not moving and not engaged in combat but has a run back location set then clear the runback location
@@ -2964,6 +2971,8 @@ void Spawn::ResetMovement(bool inFlight){
 	movement_loop.clear();
 	movement_index = 0;
 	resume_movement = true;
+	ClearRunningLocations();
+
 	if(!inFlight)
 		MMovementLoop.releasewritelock();
 }
@@ -2987,10 +2996,21 @@ void Spawn::AddMovementLocation(float x, float y, float z, float speed, int16 de
 }
 
 bool Spawn::IsRunning(){
-	if(movement_locations && movement_locations->size() > 0)
-		return true;
-	else
-		return false;
+	bool movement = false;
+
+	if(movement_locations && MMovementLocations)
+	{
+		MMovementLocations->readlock(__FUNCTION__, __LINE__);
+		movement = movement_locations->size() > 0;
+		MMovementLocations->releasereadlock(__FUNCTION__, __LINE__);
+		if(movement)
+			return true;
+	}
+
+	MMovementLoop.lock();
+	movement = movement_loop.size() > 0;
+	MMovementLoop.unlock();
+	return movement;
 }
 
 void Spawn::RunToLocation(float x, float y, float z, float following_x, float following_y, float following_z){
@@ -3163,7 +3183,8 @@ bool Spawn::CalculateChange(){
 			tar_vz = (tar_vz / len) * speed;
 
 			// Distance less then 0.5 just set the npc to the target location
-			if (GetDistance(data->x, data->y, data->z, IsWidget() ? false : true) <= 0.5f) {
+			float dist = (data->speed > 0.5f) ? data->speed : 0.5f;
+			if (GetDistance(data->x, data->y, data->z, IsWidget() ? false : true) <= dist) {
 				SetX(data->x, false);
 				SetZ(data->z, false);
 				SetY(data->y, false, true);
@@ -3180,7 +3201,7 @@ bool Spawn::CalculateChange(){
 			if (GetMap() != nullptr) {
 				Cell* newCell = GetMap()->GetGrid()->GetCell(GetX(), GetZ());
 				int32 newGrid = GetMap()->GetGrid()->GetGridID(this);
-				if (!IsFlyingCreature() && newGrid != 0 && newGrid != appearance.pos.grid_id)
+				if ((!IsFlyingCreature() || IsTransportSpawn()) && newGrid != 0 && newGrid != appearance.pos.grid_id)
 					SetPos(&(appearance.pos.grid_id), newGrid);
 			}
 		}
@@ -3231,7 +3252,13 @@ void Spawn::CalculateRunningLocation(bool stop){
 		}
 		else
 			((Entity*)this)->HaltMovement();
-	} 
+	}
+	else if (!following)
+	{
+		position_changed = true;
+		changed = true;
+		GetZone()->AddChangedSpawn(this);
+	}
 }
 float Spawn::GetFaceTarget(float x, float z) {
 	float angle;
@@ -4129,4 +4156,35 @@ void Spawn::SetWaterCreature() {
 		((Entity*)this)->GetInfoStruct()->set_water_type(0);
 		break;
 	}
+}
+
+void Spawn::AddRailPassenger(int32 char_id)
+{
+	std::lock_guard<std::mutex> lk(m_RailMutex);
+	rail_passengers.insert(make_pair(char_id,true));
+}
+
+void Spawn::RemoveRailPassenger(int32 char_id)
+{
+	std::lock_guard<std::mutex> lk(m_RailMutex);
+	std::map<int32, bool>::iterator itr = rail_passengers.find(char_id);
+	if(itr != rail_passengers.end())
+		rail_passengers.erase(itr);
+}
+
+vector<Spawn*> Spawn::GetPassengersOnRail() {
+	vector<Spawn*> tmp_list;
+	Spawn* spawn;
+	m_RailMutex.lock();
+	std::map<int32, bool>::iterator itr = rail_passengers.begin();
+	while(itr != rail_passengers.end()){
+		Client* client = zone_list.GetClientByCharID(itr->first);
+		if(!client || !client->GetPlayer())
+			continue;
+
+		tmp_list.push_back(client->GetPlayer());
+		itr++;
+	}
+	m_RailMutex.unlock();
+	return tmp_list;
 }

+ 6 - 0
EQ2/source/WorldServer/Spawn.h

@@ -39,6 +39,7 @@
 #include "MutexList.h"
 #include <deque>
 #include <memory> // needed for LS to compile properly on linux
+#include <mutex>
 
 #define DAMAGE_PACKET_TYPE_SIPHON_SPELL		0x41
 #define DAMAGE_PACKET_TYPE_SIPHON_SPELL2	0x49
@@ -1212,6 +1213,9 @@ public:
 	
 	sint64 GetRailID() { return rail_id; }
 	void SetRailID(sint64 val) { rail_id = val; }
+	void AddRailPassenger(int32 char_id);
+	void RemoveRailPassenger(int32 char_id);
+	vector<Spawn*> GetPassengersOnRail();
 protected:
 
 	bool	has_quests_required;
@@ -1314,6 +1318,8 @@ private:
 
 	bool is_transport_spawn;
 	sint64 rail_id;
+	map<int32, bool> rail_passengers;
+	mutex m_RailMutex;
 };
 
 #endif

+ 2 - 0
EQ2/source/WorldServer/client.h

@@ -485,6 +485,8 @@ public:
 	void TriggerSpellSave();
 
 	void ClearSentItemDetails() { sent_item_details.clear(); }
+
+	bool IsPlayerLoadingComplete() { return player_loading_complete; }
 private:
 	void    SavePlayerImages();
 	void	SkillChanged(Skill* skill, int16 previous_value, int16 new_value);

+ 36 - 11
EQ2/source/WorldServer/zoneserver.cpp

@@ -1168,7 +1168,7 @@ void ZoneServer::CheckRemoveSpawnFromClient(Spawn* spawn) {
 				client->GetPlayer()->WasSentSpawn(spawn->GetID()) && 
 				client->GetPlayer()->WasSpawnRemoved(spawn) == false && 
 				(spawn_range_map.Get(client)->Get(spawn->GetID()) > REMOVE_SPAWN_DISTANCE &&
-					!spawn->IsSign() && !spawn->IsObject() && !spawn->IsWidget())){
+					!spawn->IsSign() && !spawn->IsObject() && !spawn->IsWidget() && !spawn->IsTransportSpawn())){
 				SendRemoveSpawn(client, spawn, packet);
 				spawn_range_map.Get(client)->erase(spawn->GetID());
 			}
@@ -1752,7 +1752,7 @@ void ZoneServer::SendSpawnChangesByDBID(int32 db_id, Client* client, bool overri
 }
 
 void ZoneServer::SendSpawnChanges(Spawn* spawn, Client* client, bool override_changes, bool override_vis_changes){
-	if(client && client->IsReadyForUpdates() && client->GetPlayer()->WasSentSpawn(spawn->GetID()) && !client->GetPlayer()->WasSpawnRemoved(spawn) && client->GetPlayer()->GetDistance(spawn) < SEND_SPAWN_DISTANCE){
+	if(client && client->IsReadyForUpdates() && client->GetPlayer()->WasSentSpawn(spawn->GetID()) && !client->GetPlayer()->WasSpawnRemoved(spawn) && (spawn->IsTransportSpawn() || client->GetPlayer()->GetDistance(spawn) < SEND_SPAWN_DISTANCE)){
 		EQ2Packet* outapp = spawn->spawn_update_packet(client->GetPlayer(), client->GetVersion(), override_changes, override_vis_changes);
 		if(outapp)
 			client->QueuePacket(outapp);
@@ -2741,6 +2741,14 @@ bool ZoneServer::CallSpawnScript(Spawn* npc, int8 type, Spawn* spawn, const char
 				result = lua_interface->RunSpawnScript(script, "usedoor", npc, spawn, "", is_door_open);
 				break;
 			}
+			case SPAWN_SCRIPT_BOARD: {
+				result = lua_interface->RunSpawnScript(script, "board", npc, spawn);
+				break;
+			}
+			case SPAWN_SCRIPT_EMBARK: {
+				result = lua_interface->RunSpawnScript(script, "embark", npc, spawn);
+				break;
+			}
 			default:
 			{
 				result = false;
@@ -5748,7 +5756,8 @@ void ZoneServer::RemoveSpawnSupportFunctions(Spawn* spawn) {
 		return;	
 
 	LogWrite(ZONE__DEBUG, 7, "Zone", "Processing RemoveSpawnSupportFunctions...");
-
+	if(spawn->IsPlayer() && spawn->GetZone())
+		spawn->GetZone()->RemovePlayerPassenger(((Player*)spawn)->GetCharacterID());
 	if(spawn->IsEntity())
 		RemoveSpellTimersFromSpawn((Entity*)spawn, true);
 
@@ -6282,6 +6291,7 @@ Spawn* ZoneServer::GetTransportByRailID(sint64 rail_id){
 	vector<int32>::iterator itr = transport_spawns.begin();
 	while(itr != transport_spawns.end()){
 		spawn = GetSpawnByID(*itr);
+		//printf("Rail id: %i vs %i\n", spawn ? spawn->GetRailID() : 0, rail_id);
 		if(spawn && spawn->GetRailID() == rail_id){
 			closest_spawn = spawn;
 			break;
@@ -6536,19 +6546,34 @@ vector<Spawn*> ZoneServer::GetSpawnsByID(int32 id) {
 vector<Spawn*> ZoneServer::GetSpawnsByRailID(sint64 rail_id) {
 	vector<Spawn*> tmp_list;
 	Spawn* spawn;
-
-	map<int32, Spawn*>::iterator itr;
-	MSpawnList.readlock(__FUNCTION__, __LINE__);
-	for (itr = spawn_list.begin(); itr != spawn_list.end(); itr++) {
-		spawn = itr->second;
-		if (spawn && (spawn->GetRailID() == rail_id))
+	MTransportSpawns.readlock(__FUNCTION__, __LINE__);
+	vector<int32>::iterator itr = transport_spawns.begin();
+	while(itr != transport_spawns.end()){
+		spawn = GetSpawnByID(*itr);
+		if(spawn && spawn->GetRailID() == rail_id){
 			tmp_list.push_back(spawn);
+		}
+		itr++;
 	}
-	MSpawnList.releasereadlock(__FUNCTION__, __LINE__);
-
+	MTransportSpawns.releasereadlock(__FUNCTION__, __LINE__);
 	return tmp_list;
 }
 
+void ZoneServer::RemovePlayerPassenger(int32 char_id) {
+	vector<Spawn*> tmp_list;
+	Spawn* spawn;
+	MTransportSpawns.readlock(__FUNCTION__, __LINE__);
+	vector<int32>::iterator itr = transport_spawns.begin();
+	while(itr != transport_spawns.end()){
+		spawn = GetSpawnByID(*itr);
+		if(spawn) {
+			spawn->RemoveRailPassenger(char_id);
+		}
+		itr++;
+	}
+	MTransportSpawns.releasereadlock(__FUNCTION__, __LINE__);
+}
+
 vector<Spawn*> ZoneServer::GetAttackableSpawnsByDistance(Spawn* caster, float distance) {
 	vector<Spawn*> ret;
 	Spawn* spawn = 0;

+ 3 - 0
EQ2/source/WorldServer/zoneserver.h

@@ -88,6 +88,8 @@ class Bot;
 #define SPAWN_SCRIPT_HEAR_SAY			18
 #define SPAWN_SCRIPT_PRESPAWN			19
 #define SPAWN_SCRIPT_USEDOOR			20
+#define SPAWN_SCRIPT_BOARD				21
+#define SPAWN_SCRIPT_EMBARK				22
 
 #define SPAWN_CONDITIONAL_NONE			0
 #define SPAWN_CONDITIONAL_DAY			1
@@ -463,6 +465,7 @@ public:
 	void			AddTransportSpawn(Spawn* spawn);
 	vector<Spawn*>	GetSpawnsByID(int32 id);
 	vector<Spawn*>	GetSpawnsByRailID(sint64 rail_id);
+	void			RemovePlayerPassenger(int32 char_id);
 	bool			IsDusk() { return isDusk; }										// never used, probably meant for lua though