Browse Source

- Completed Fix #279
- Update Activities for AOM added (someday we need a table based on versions to handle these)
- In turn of updating activities, client side enforced drowning, swimming is now correct
- transmuting skill / item stat now calculated
- Fixed sending certain information to client before they are zoned in
- Player is blocked from being attacked until they send their 'ready' message to the server (visual UI display can be seen)
- New swim rules:
RULE_INIT(R_Player, SwimmingSkillMinSpeed, "20");
RULE_INIT(R_Player, SwimmingSkillMaxSpeed, "200");

RULE_INIT(R_Player, SwimmingSkillMinBreathLength, "30"); // these are probably in seconds
RULE_INIT(R_Player, SwimmingSkillMaxBreathLength, "1000");

Emagi 1 year ago
parent
commit
1e2d5f98cf

+ 56 - 13
EQ2/source/WorldServer/Player.cpp

@@ -840,7 +840,22 @@ EQ2Packet* PlayerInfo::serialize(int16 version, int16 modifyPos, int32 modifyVal
 		packet->setDataByName("curse_count", 49);// added with spells leave here for testing//dov confirmed
 	//	packet->setDataByName("unknown_1096_17_MJ", 30);//unknown_1096_17_MJ
 		//////Maintained effects go here, but are below
-		packet->setDataByName("breath", 30);
+		
+		Skill* skill = player->GetSkillByName("Swimming", false);
+		float breath_modifier = rule_manager.GetGlobalRule(R_Player, SwimmingSkillMinBreathLength)->GetFloat();
+		if(skill) {
+			int32 max_val = 450;
+			if(skill->max_val > 0)
+				max_val = skill->max_val;
+			float diff = (float)(skill->current_val + player->GetStat(ITEM_STAT_SWIMMING)) / (float)max_val;
+			float max_breath_mod = rule_manager.GetGlobalRule(R_Player, SwimmingSkillMaxBreathLength)->GetFloat();
+			float diff_mod = max_breath_mod * diff;
+			if(diff_mod > max_breath_mod)
+				breath_modifier = max_breath_mod;
+			else if(diff_mod > breath_modifier)
+				breath_modifier = diff_mod;
+		}
+		packet->setDataByName("breath", breath_modifier);
 		//packet->setDataByName("unknown_1096_18_MJ", 1000);//16880
 		packet->setDataByName("melee_pri_dmg_min", player->GetPrimaryWeaponMinDamage());// dov confirmed
 		packet->setDataByName("melee_pri_dmg_max", player->GetPrimaryWeaponMaxDamage());// dov confirmed
@@ -3665,17 +3680,45 @@ void Player::PrepareIncomingMovementPacket(int32 len, uchar* data, int16 version
 
 	SetHeading((sint16)(direction1 * 64), (sint16)(direction2 * 64));
 	if (activity != last_movement_activity) {
-		if (GetZone() && GetZone()->GetDrowningVictim(this) && (activity == UPDATE_ACTIVITY_RUNNING || activity == UPDATE_ACTIVITY_IN_WATER_ABOVE)) // not drowning anymore
-			GetZone()->RemoveDrowningVictim(this);
-
-		if ((activity == UPDATE_ACTIVITY_DROWNING || activity == UPDATE_ACTIVITY_DROWNING2) && GetZone() && !GetInvulnerable()) //drowning
-			GetZone()->AddDrowningVictim(this);
-
-		if (activity == UPDATE_ACTIVITY_JUMPING || activity == UPDATE_ACTIVITY_FALLING)
-			SetInitialState(1024);
-		else if (GetInitialState() == 1024)
-			SetInitialState(16512);
-
+		switch(activity) {
+			case UPDATE_ACTIVITY_RUNNING:
+			case UPDATE_ACTIVITY_RUNNING_AOM:
+			case UPDATE_ACTIVITY_IN_WATER_ABOVE:
+			case UPDATE_ACTIVITY_IN_WATER_BELOW:
+			case UPDATE_ACTIVITY_MOVE_WATER_ABOVE_AOM:
+			case UPDATE_ACTIVITY_MOVE_WATER_BELOW_AOM: {
+				if(GetZone() && GetZone()->GetDrowningVictim(this))
+					GetZone()->RemoveDrowningVictim(this);
+				
+				break;
+			}
+			case UPDATE_ACTIVITY_DROWNING:
+			case UPDATE_ACTIVITY_DROWNING2:
+			case UPDATE_ACTIVITY_DROWNING_AOM:
+			case UPDATE_ACTIVITY_DROWNING2_AOM: {
+				if(GetZone() && !GetInvulnerable()) {
+					GetZone()->AddDrowningVictim(this);
+				}
+				break;
+			}
+			case UPDATE_ACTIVITY_JUMPING:
+			case UPDATE_ACTIVITY_FALLING:
+			case UPDATE_ACTIVITY_FALLING_AOM: {
+				if(GetInitialState() != 1024) {
+					SetInitialState(1024);
+				}
+				else if(GetInitialState() == 1024) {
+					if(activity == UPDATE_ACTIVITY_JUMPING_AOM) {
+						SetInitialState(UPDATE_ACTIVITY_JUMPING_AOM);
+					}
+					else {
+						SetInitialState(16512);
+					}	
+				}
+				break;
+			}
+		}
+		
 		last_movement_activity = activity;
 	}
 
@@ -3774,7 +3817,7 @@ void Player::PrepareIncomingMovementPacket(int32 len, uchar* data, int16 version
 		appearance.pos.grid_id = grid_id;
 	}
 	if (activity == UPDATE_ACTIVITY_IN_WATER_ABOVE || activity == UPDATE_ACTIVITY_IN_WATER_BELOW) {
-		if (MakeRandomFloat(0, 100) < 25)
+		if (MakeRandomFloat(0, 100) < 25 && InWater())
 			GetSkillByName("Swimming", true);
 	}
 	// don't have to uncomment the print packet but you MUST uncomment the safe_delete() for xml structs

+ 12 - 0
EQ2/source/WorldServer/Player.h

@@ -113,6 +113,18 @@
 #define UPDATE_ACTIVITY_DROWNING		14464
 #define UPDATE_ACTIVITY_DROWNING2		14336
 
+
+
+#define UPDATE_ACTIVITY_FALLING_AOM			16384
+#define UPDATE_ACTIVITY_RIDING_BOAT_AOM     256
+#define UPDATE_ACTIVITY_RUNNING_AOM			16512
+#define UPDATE_ACTIVITY_JUMPING_AOM			17408
+#define UPDATE_ACTIVITY_MOVE_WATER_BELOW_AOM	22528
+#define UPDATE_ACTIVITY_MOVE_WATER_ABOVE_AOM	22656
+#define UPDATE_ACTIVITY_SITTING_AOM			22720
+#define UPDATE_ACTIVITY_DROWNING_AOM		30720
+#define UPDATE_ACTIVITY_DROWNING2_AOM		30848
+
 #define NUM_MAINTAINED_EFFECTS	30
 #define NUM_SPELL_EFFECTS		45
 

+ 6 - 0
EQ2/source/WorldServer/Rules/Rules.cpp

@@ -214,6 +214,12 @@ void RuleManager::Init()
 	RULE_INIT(R_Player, MentorItemDecayRate, ".05"); // 5% per level lost when mentoring
 	RULE_INIT(R_Player, TemporaryItemLogoutTime, "1800.0"); // time in seconds (double) for temporary item to decay after being logged out for a period of time, 30 min is the default
 	RULE_INIT(R_Player, HeirloomItemShareExpiration, "172800.0"); // 2 days ('48 hours') in seconds
+	RULE_INIT(R_Player, SwimmingSkillMinSpeed, "20"); 
+	RULE_INIT(R_Player, SwimmingSkillMaxSpeed, "200");
+	
+	RULE_INIT(R_Player, SwimmingSkillMinBreathLength, "30");
+	RULE_INIT(R_Player, SwimmingSkillMaxBreathLength, "1000");
+	
 	/* PVP */
 	RULE_INIT(R_PVP, AllowPVP, "0");
 	RULE_INIT(R_PVP, LevelRange, "4");

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

@@ -74,6 +74,10 @@ enum RuleType {
 	MentorItemDecayRate,
 	TemporaryItemLogoutTime,
 	HeirloomItemShareExpiration,
+	SwimmingSkillMinSpeed,
+	SwimmingSkillMaxSpeed,
+	SwimmingSkillMinBreathLength,
+	SwimmingSkillMaxBreathLength,
 
 	/* PVP */
 	AllowPVP,

+ 15 - 1
EQ2/source/WorldServer/Spawn.cpp

@@ -2129,7 +2129,21 @@ void Spawn::InitializePosPacketData(Player* player, PacketStruct* packet, bool b
 	}
 
 	if (IsPlayer()) {
-		packet->setDataByName("pos_swim_speed_modifier", 20);
+		Skill* skill = ((Player*)this)->GetSkillByName("Swimming", false);
+		sint16 swim_modifier = rule_manager.GetGlobalRule(R_Player, SwimmingSkillMinSpeed)->GetSInt16();
+		if(skill) {
+			sint16 max_val = 450;
+			if(skill->max_val > 0)
+				max_val = skill->max_val;
+			sint16 max_swim_mod = rule_manager.GetGlobalRule(R_Player, SwimmingSkillMaxSpeed)->GetSInt16();
+			float diff = (float)(skill->current_val + ((Player*)this)->GetStat(ITEM_STAT_SWIMMING)) / (float)max_val;
+			sint16 diff_mod = (sint16)(float)max_swim_mod * diff;
+			if(diff_mod > max_swim_mod)
+				swim_modifier = max_swim_mod;
+			else if(diff_mod > swim_modifier)
+				swim_modifier = diff_mod;
+		}
+		packet->setDataByName("pos_swim_speed_modifier", swim_modifier);
 		packet->setDataByName("pos_x_velocity", TransformFromFloat(GetSpeedX(), 5));
 		packet->setDataByName("pos_y_velocity", TransformFromFloat(GetSpeedY(), 5));
 		packet->setDataByName("pos_z_velocity", TransformFromFloat(GetSpeedZ(), 5));

+ 7 - 6
EQ2/source/WorldServer/Transmute.cpp

@@ -94,9 +94,10 @@ void Transmute::HandleItemResponse(Client* client, Player* player, int32 req_id,
 	Skill* skill = player->GetSkillByName("Transmuting");
 
 	int32 required_skill = (std::max<int32>(item_level, 5) - 5) * 5;
-	if (!skill || skill->current_val < required_skill) {
+	sint32 item_stat_bonus = player->GetStat(ITEM_STAT_TRANSMUTING);
+	if (!skill || (skill->current_val+item_stat_bonus) < required_skill) {
 		client->Message(CHANNEL_COLOR_RED, "You need at least %u Transmuting skill to transmute the %s."
-			" You have %u Transmuting skill.", required_skill, item->name.c_str(), skill ? skill->current_val : 0);
+			" You have %u Transmuting skill.", required_skill, item->name.c_str(), skill ? (skill->current_val+item_stat_bonus) : 0);
 		return;
 	}
 
@@ -284,15 +285,15 @@ void Transmute::CompleteTransmutation(Client* client, Player* player) {
 
 	//Skill up roll
 	int32 max_trans_level = skill->current_val / 5 + 5;
-	int32 level_dif = max_trans_level - item_level;
-	if (level_dif >= 5 || skill->current_val >= skill->max_val) {
+	sint32 level_dif = (sint32)max_trans_level - (sint32)item_level;
+	if (level_dif > 10 || skill->current_val >= skill->max_val) {
 		//No skill up possible
 		LogWrite(SKILL__DEBUG, 7, "Skill", "Transmuting skill up not possible.  level_dif = %u, skill val = %u, skill max val = %u", level_dif, skill->current_val, skill->max_val);
 		return;
 	}
 	
-	//40% Base chance of a skillup at max item level, 20% overall decrease per level difference
-	const int32 SKILLUP_PERCENT_CHANCE_MAX = 40;
+	//50% Base chance of a skillup at max item level, 20% overall decrease per level difference
+	const int32 SKILLUP_PERCENT_CHANCE_MAX = 50;
 	int32 required_roll = SKILLUP_PERCENT_CHANCE_MAX * (1.f - (item_level <= 5 ?  0.f : (level_dif * .2f)));
 	roll = MakeRandomInt(1, 100);
 	//LogWrite(SKILL__ERROR, 0, "Skill", "Skill up roll results, roll = %u, required_roll = %u", roll, required_roll);

+ 6 - 6
EQ2/source/WorldServer/zoneserver.cpp

@@ -702,7 +702,7 @@ void ZoneServer::RegenUpdate(){
 				((Entity*)spawn)->DoRegenUpdate();
 			if(spawn->IsPlayer()){
 				Client* client = GetClientBySpawn(spawn);
-				if(client && client->IsConnected())
+				if(client && client->IsReadyForUpdates())
 					client->QueuePacket(client->GetPlayer()->GetPlayerInfo()->serialize(client->GetVersion()));
 			}
 		}
@@ -909,7 +909,7 @@ bool ZoneServer::CheckNPCAttacks(NPC* npc, Spawn* victim, Client* client){
 		return true;
 
 	if (client) {
-		if (client->IsConnected() && npc->CanSeeInvis(client->GetPlayer()) && client->GetPlayer()->GetFactions()->ShouldAttack(npc->GetFactionID()) && npc->AttackAllowed((Entity*)victim, false)) {
+		if (client->IsReadyForUpdates() && npc->CanSeeInvis(client->GetPlayer()) && client->GetPlayer()->GetFactions()->ShouldAttack(npc->GetFactionID()) && npc->AttackAllowed((Entity*)victim, false)) {
 			if (!npc->EngagedInCombat() && client->GetPlayer()->GetArrowColor(npc->GetLevel()) != ARROW_COLOR_GRAY) {
 				AggroVictim(npc, victim, client);
 			}
@@ -3648,7 +3648,7 @@ void ZoneServer::PlayFlavor(Spawn* spawn, const char* mp3, const char* text, con
 	MClientList.readlock(__FUNCTION__, __LINE__);
 	for (client_itr = clients.begin(); client_itr != clients.end(); client_itr++) {
 		client = *client_itr;
-		if(!client || !client->IsConnected() || !client->GetPlayer()->WasSentSpawn(spawn->GetID()) || client->GetPlayer()->GetDistance(spawn) > 30)
+		if(!client || !client->IsReadyForUpdates() || !client->GetPlayer()->WasSentSpawn(spawn->GetID()) || client->GetPlayer()->GetDistance(spawn) > 30)
 			continue;
 		PlayFlavor(client, spawn, mp3, text, emote, key1, key2, language);
 	}
@@ -3665,7 +3665,7 @@ void ZoneServer::PlayVoice(Spawn* spawn, const char* mp3, int32 key1, int32 key2
 	MClientList.readlock(__FUNCTION__, __LINE__);
 	for (client_itr = clients.begin(); client_itr != clients.end(); client_itr++) {
 		client = *client_itr;
-		if(!client || !client->IsConnected() || !client->GetPlayer()->WasSentSpawn(spawn->GetID()))
+		if(!client || !client->IsReadyForUpdates() || !client->GetPlayer()->WasSentSpawn(spawn->GetID()))
 			continue;
 		PlayVoice(client, spawn, mp3, key1, key2);
 	}
@@ -3715,7 +3715,7 @@ void ZoneServer::PlaySoundFile(Client* client, const char* name, float origin_x,
 					outapp = packet->serialize();
 				}
 			}
-			if(outapp && client && client->IsConnected())
+			if(outapp && client && client->IsReadyForUpdates())
 				client->QueuePacket(outapp->Copy());
 		}
 		MClientList.releasereadlock(__FUNCTION__, __LINE__);
@@ -5812,7 +5812,7 @@ void ZoneServer::CheckLocationProximity() {
 		MutexList<Client*>::iterator iterator = connected_clients.begin();
 		while(iterator.Next()){
 			client = iterator->value;
-			if (client->IsConnected() && client->IsReadyForSpawns() && !client->IsZoning()) {
+			if (client->IsConnected() && client->IsReadyForUpdates() && !client->IsZoning()) {
 				try {
 					MutexList<LocationProximity*>::iterator itr = location_proximities.begin();
 					LocationProximity* prox = 0;