[12697] Improve alcohol handling

Fixes client crash when using Barbershop Chair while drunk

Also allow .mod drunk to modify the drunk state of the targeted player (original author @Shauren)
This commit is contained in:
sanctum32 2013-10-21 08:48:15 +03:00 committed by Antz
parent 4cebb3880c
commit 7ae2fd2a6e
8 changed files with 60 additions and 55 deletions

View file

@ -434,7 +434,7 @@ DROP TABLE IF EXISTS `character_db_version`;
/*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */; /*!40101 SET character_set_client = utf8 */;
CREATE TABLE `character_db_version` ( CREATE TABLE `character_db_version` (
`required_12631_01_characters_corpse` bit(1) default NULL `required_12697_01_characters_characters` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Last applied sql update to DB'; ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Last applied sql update to DB';
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
@ -444,7 +444,7 @@ CREATE TABLE `character_db_version` (
LOCK TABLES `character_db_version` WRITE; LOCK TABLES `character_db_version` WRITE;
/*!40000 ALTER TABLE `character_db_version` DISABLE KEYS */; /*!40000 ALTER TABLE `character_db_version` DISABLE KEYS */;
INSERT INTO `character_db_version` (`required_12631_01_characters_corpse`) VALUES INSERT INTO `character_db_version` (`required_12697_01_characters_characters`) VALUES
(NULL); (NULL);
/*!40000 ALTER TABLE `character_db_version` ENABLE KEYS */; /*!40000 ALTER TABLE `character_db_version` ENABLE KEYS */;
UNLOCK TABLES; UNLOCK TABLES;
@ -1172,7 +1172,7 @@ CREATE TABLE `characters` (
`yesterdayKills` smallint(5) unsigned NOT NULL DEFAULT '0', `yesterdayKills` smallint(5) unsigned NOT NULL DEFAULT '0',
`chosenTitle` int(10) unsigned NOT NULL DEFAULT '0', `chosenTitle` int(10) unsigned NOT NULL DEFAULT '0',
`watchedFaction` int(10) unsigned NOT NULL DEFAULT '0', `watchedFaction` int(10) unsigned NOT NULL DEFAULT '0',
`drunk` smallint(5) unsigned NOT NULL DEFAULT '0', `drunk` tinyint(3) unsigned NOT NULL DEFAULT '0',
`health` int(10) unsigned NOT NULL DEFAULT '0', `health` int(10) unsigned NOT NULL DEFAULT '0',
`power1` int(10) unsigned NOT NULL DEFAULT '0', `power1` int(10) unsigned NOT NULL DEFAULT '0',
`power2` int(10) unsigned NOT NULL DEFAULT '0', `power2` int(10) unsigned NOT NULL DEFAULT '0',

View file

@ -0,0 +1,4 @@
ALTER TABLE character_db_version CHANGE COLUMN required_12631_01_characters_corpse required_12697_01_characters_characters bit;
UPDATE characters SET drunk = (drunk / 256) & 0xFF;
ALTER TABLE characters CHANGE drunk drunk tinyint(3) unsigned NOT NULL DEFAULT '0';

View file

@ -2277,15 +2277,15 @@ bool ChatHandler::HandleGoGridCommand(char* args)
bool ChatHandler::HandleModifyDrunkCommand(char* args) bool ChatHandler::HandleModifyDrunkCommand(char* args)
{ {
if (!*args) return false; if (!*args)
return false;
uint32 drunklevel = (uint32)atoi(args); uint8 drunkValue = (uint8)atoi(args);
if (drunklevel > 100) if (drunkValue > 100)
drunklevel = 100; drunkValue = 100;
uint16 drunkMod = drunklevel * 0xFFFF / 100; if (Player* target = getSelectedPlayer())
target->SetDrunkValue(drunkValue);
m_session->GetPlayer()->SetDrunkValue(drunkMod);
return true; return true;
} }

View file

@ -463,7 +463,6 @@ Player::Player(WorldSession* session): Unit(), m_mover(this), m_camera(this), m_
m_isInWater = false; m_isInWater = false;
m_drunkTimer = 0; m_drunkTimer = 0;
m_drunk = 0;
m_restTime = 0; m_restTime = 0;
m_deathTimer = 0; m_deathTimer = 0;
m_deathExpireTime = 0; m_deathExpireTime = 0;
@ -679,7 +678,7 @@ bool Player::Create(uint32 guidlow, const std::string& name, uint8 race, uint8 c
SetByteValue(PLAYER_BYTES_2, 0, facialHair); SetByteValue(PLAYER_BYTES_2, 0, facialHair);
SetByteValue(PLAYER_BYTES_2, 3, REST_STATE_NORMAL); SetByteValue(PLAYER_BYTES_2, 3, REST_STATE_NORMAL);
SetUInt16Value(PLAYER_BYTES_3, 0, gender); // only GENDER_MALE/GENDER_FEMALE (1 bit) allowed, drunk state = 0 SetByteValue(PLAYER_BYTES_3, 0, gender);
SetByteValue(PLAYER_BYTES_3, 3, 0); // BattlefieldArenaFaction (0 or 1) SetByteValue(PLAYER_BYTES_3, 3, 0); // BattlefieldArenaFaction (0 or 1)
SetInGuild(0); SetInGuild(0);
@ -1121,34 +1120,41 @@ void Player::HandleDrowning(uint32 time_diff)
m_MirrorTimerFlagsLast = m_MirrorTimerFlags; m_MirrorTimerFlagsLast = m_MirrorTimerFlags;
} }
/// The player sobers by 256 every 10 seconds // The player sobers by 1% every 9 seconds
void Player::HandleSobering() void Player::HandleSobering()
{ {
m_drunkTimer = 0; uint8 currentDrunkValue = GetDrunkValue();
if (currentDrunkValue)
uint32 drunk = (m_drunk <= 256) ? 0 : (m_drunk - 256); {
SetDrunkValue(drunk); --currentDrunkValue;
SetDrunkValue(currentDrunkValue);
}
} }
DrunkenState Player::GetDrunkenstateByValue(uint16 value) DrunkenState Player::GetDrunkenstateByValue(uint8 value)
{ {
if (value >= 23000) if (value >= 90)
return DRUNKEN_SMASHED; return DRUNKEN_SMASHED;
if (value >= 12800) if (value >= 50)
return DRUNKEN_DRUNK; return DRUNKEN_DRUNK;
if (value & 0xFFFE) if (value)
return DRUNKEN_TIPSY; return DRUNKEN_TIPSY;
return DRUNKEN_SOBER; return DRUNKEN_SOBER;
} }
void Player::SetDrunkValue(uint16 newDrunkenValue, uint32 itemId) void Player::SetDrunkValue(uint8 newDrunkValue, uint32 itemId /*= 0*/)
{ {
uint32 oldDrunkenState = Player::GetDrunkenstateByValue(m_drunk); if (newDrunkValue > 100)
newDrunkValue = 100;
m_drunk = newDrunkenValue; if (newDrunkValue < GetDrunkValue())
SetUInt16Value(PLAYER_BYTES_3, 0, uint16(getGender()) | (m_drunk & 0xFFFE)); m_drunkTimer = 0; // reset sobering timer
uint32 newDrunkenState = Player::GetDrunkenstateByValue(m_drunk); uint32 oldDrunkenState = Player::GetDrunkenstateByValue(GetDrunkValue());
SetByteValue(PLAYER_BYTES_3, 1, newDrunkValue);
uint32 newDrunkenState = Player::GetDrunkenstateByValue(newDrunkValue);
// special drunk invisibility detection // special drunk invisibility detection
if (newDrunkenState >= DRUNKEN_DRUNK) if (newDrunkenState >= DRUNKEN_DRUNK)
@ -1365,11 +1371,11 @@ void Player::Update(uint32 update_diff, uint32 p_time)
m_Last_tick = now; m_Last_tick = now;
} }
if (m_drunk) if (GetDrunkValue())
{ {
m_drunkTimer += update_diff; m_drunkTimer += update_diff;
if (m_drunkTimer > 10 * IN_MILLISECONDS) if (m_drunkTimer > 9 * IN_MILLISECONDS)
HandleSobering(); HandleSobering();
} }
@ -15454,7 +15460,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SqlQueryHolder* holder)
SetByteValue(UNIT_FIELD_BYTES_0, 0, fields[3].GetUInt8()); // race SetByteValue(UNIT_FIELD_BYTES_0, 0, fields[3].GetUInt8()); // race
SetByteValue(UNIT_FIELD_BYTES_0, 1, fields[4].GetUInt8()); // class SetByteValue(UNIT_FIELD_BYTES_0, 1, fields[4].GetUInt8()); // class
uint8 gender = fields[5].GetUInt8() & 0x01; // allowed only 1 bit values male/female cases (for fit drunk gender part) uint8 gender = fields[5].GetUInt8() & 0x01;
SetByteValue(UNIT_FIELD_BYTES_0, 2, gender); // gender SetByteValue(UNIT_FIELD_BYTES_0, 2, gender); // gender
SetUInt32Value(UNIT_FIELD_LEVEL, fields[6].GetUInt8()); SetUInt32Value(UNIT_FIELD_LEVEL, fields[6].GetUInt8());
@ -15479,9 +15485,8 @@ bool Player::LoadFromDB(ObjectGuid guid, SqlQueryHolder* holder)
SetUInt32Value(PLAYER_BYTES, fields[9].GetUInt32()); SetUInt32Value(PLAYER_BYTES, fields[9].GetUInt32());
SetUInt32Value(PLAYER_BYTES_2, fields[10].GetUInt32()); SetUInt32Value(PLAYER_BYTES_2, fields[10].GetUInt32());
m_drunk = fields[45].GetUInt16(); SetByteValue(PLAYER_BYTES_3, 0, gender);
SetByteValue(PLAYER_BYTES_3, 1, fields[45].GetUInt8());
SetUInt16Value(PLAYER_BYTES_3, 0, (m_drunk & 0xFFFE) | gender);
SetUInt32Value(PLAYER_FLAGS, fields[11].GetUInt32()); SetUInt32Value(PLAYER_FLAGS, fields[11].GetUInt32());
SetInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, fields[44].GetInt32()); SetInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, fields[44].GetInt32());
@ -15713,13 +15718,11 @@ bool Player::LoadFromDB(ObjectGuid guid, SqlQueryHolder* holder)
// set value, including drunk invisibility detection // set value, including drunk invisibility detection
// calculate sobering. after 15 minutes logged out, the player will be sober again // calculate sobering. after 15 minutes logged out, the player will be sober again
float soberFactor; uint8 newDrunkValue = 0;
if (time_diff > 15 * MINUTE) if (time_diff < uint32(GetDrunkValue()) * 9)
soberFactor = 0; newDrunkValue = GetDrunkValue() - time_diff / 9;
else
soberFactor = 1 - time_diff / (15.0f * MINUTE); SetDrunkValue(newDrunkValue);
uint16 newDrunkenValue = uint16(soberFactor * m_drunk);
SetDrunkValue(newDrunkenValue);
m_cinematic = fields[18].GetUInt32(); m_cinematic = fields[18].GetUInt32();
m_Played_time[PLAYED_TIME_TOTAL] = fields[19].GetUInt32(); m_Played_time[PLAYED_TIME_TOTAL] = fields[19].GetUInt32();
@ -17370,7 +17373,7 @@ void Player::SaveToDB()
// FIXME: at this moment send to DB as unsigned, including unit32(-1) // FIXME: at this moment send to DB as unsigned, including unit32(-1)
uberInsert.addUInt32(GetUInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX)); uberInsert.addUInt32(GetUInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX));
uberInsert.addUInt16(uint16(GetUInt32Value(PLAYER_BYTES_3) & 0xFFFE)); uberInsert.addUInt8(GetDrunkValue());
uberInsert.addUInt32(GetHealth()); uberInsert.addUInt32(GetHealth());

View file

@ -1976,9 +1976,9 @@ class MANGOS_DLL_SPEC Player : public Unit
// End of PvP System // End of PvP System
void SetDrunkValue(uint16 newDrunkValue, uint32 itemid = 0); void SetDrunkValue(uint8 newDrunkValue, uint32 itemid = 0);
uint16 GetDrunkValue() const { return m_drunk; } uint16 GetDrunkValue() const { return GetByteValue(PLAYER_BYTES_3, 1); }
static DrunkenState GetDrunkenstateByValue(uint16 value); static DrunkenState GetDrunkenstateByValue(uint8 value);
uint32 GetDeathTimer() const { return m_deathTimer; } uint32 GetDeathTimer() const { return m_deathTimer; }
uint32 GetCorpseReclaimDelay(bool pvp) const; uint32 GetCorpseReclaimDelay(bool pvp) const;
@ -2543,7 +2543,6 @@ class MANGOS_DLL_SPEC Player : public Unit
bool m_MonthlyQuestChanged; bool m_MonthlyQuestChanged;
uint32 m_drunkTimer; uint32 m_drunkTimer;
uint16 m_drunk;
uint32 m_weaponChangeTimer; uint32 m_weaponChangeTimer;
uint32 m_zoneUpdateId; uint32 m_zoneUpdateId;

View file

@ -9346,13 +9346,12 @@ void Spell::EffectInebriate(SpellEffectEntry const* /*effect*/)
return; return;
Player* player = (Player*)unitTarget; Player* player = (Player*)unitTarget;
uint16 currentDrunk = player->GetDrunkValue();
uint16 drunkMod = damage * 256; uint8 drunkValue = player->GetDrunkValue() + (uint8)damage;
if (currentDrunk + drunkMod > 0xFFFF) if (drunkValue > 100)
currentDrunk = 0xFFFF; drunkValue = 100;
else
currentDrunk += drunkMod; player->SetDrunkValue(drunkValue, m_CastItem ? m_CastItem->GetEntry() : 0);
player->SetDrunkValue(currentDrunk, m_CastItem ? m_CastItem->GetEntry() : 0);
} }
void Spell::EffectFeedPet(SpellEffectEntry const* effect) void Spell::EffectFeedPet(SpellEffectEntry const* effect)

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "12696" #define REVISION_NR "12697"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__

View file

@ -1,6 +1,6 @@
#ifndef __REVISION_SQL_H__ #ifndef __REVISION_SQL_H__
#define __REVISION_SQL_H__ #define __REVISION_SQL_H__
#define REVISION_DB_CHARACTERS "required_12631_01_characters_corpse" #define REVISION_DB_CHARACTERS "required_12697_01_characters_characters"
#define REVISION_DB_MANGOS "required_12662_01_mangos_hotfix_data" #define REVISION_DB_MANGOS "required_12662_01_mangos_hotfix_data"
#define REVISION_DB_REALMD "required_c12484_02_realmd_account_access" #define REVISION_DB_REALMD "required_c12484_02_realmd_account_access"
#endif // __REVISION_SQL_H__ #endif // __REVISION_SQL_H__