[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 character_set_client = utf8 */;
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';
/*!40101 SET character_set_client = @saved_cs_client */;
@ -444,7 +444,7 @@ CREATE TABLE `character_db_version` (
LOCK TABLES `character_db_version` WRITE;
/*!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);
/*!40000 ALTER TABLE `character_db_version` ENABLE KEYS */;
UNLOCK TABLES;
@ -1172,7 +1172,7 @@ CREATE TABLE `characters` (
`yesterdayKills` smallint(5) unsigned NOT NULL DEFAULT '0',
`chosenTitle` 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',
`power1` 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)
{
if (!*args) return false;
if (!*args)
return false;
uint32 drunklevel = (uint32)atoi(args);
if (drunklevel > 100)
drunklevel = 100;
uint8 drunkValue = (uint8)atoi(args);
if (drunkValue > 100)
drunkValue = 100;
uint16 drunkMod = drunklevel * 0xFFFF / 100;
m_session->GetPlayer()->SetDrunkValue(drunkMod);
if (Player* target = getSelectedPlayer())
target->SetDrunkValue(drunkValue);
return true;
}

View file

@ -463,7 +463,6 @@ Player::Player(WorldSession* session): Unit(), m_mover(this), m_camera(this), m_
m_isInWater = false;
m_drunkTimer = 0;
m_drunk = 0;
m_restTime = 0;
m_deathTimer = 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, 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)
SetInGuild(0);
@ -1121,34 +1120,41 @@ void Player::HandleDrowning(uint32 time_diff)
m_MirrorTimerFlagsLast = m_MirrorTimerFlags;
}
/// The player sobers by 256 every 10 seconds
// The player sobers by 1% every 9 seconds
void Player::HandleSobering()
{
m_drunkTimer = 0;
uint32 drunk = (m_drunk <= 256) ? 0 : (m_drunk - 256);
SetDrunkValue(drunk);
uint8 currentDrunkValue = GetDrunkValue();
if (currentDrunkValue)
{
--currentDrunkValue;
SetDrunkValue(currentDrunkValue);
}
}
DrunkenState Player::GetDrunkenstateByValue(uint16 value)
DrunkenState Player::GetDrunkenstateByValue(uint8 value)
{
if (value >= 23000)
return DRUNKEN_SMASHED;
if (value >= 12800)
return DRUNKEN_DRUNK;
if (value & 0xFFFE)
if (value >= 90)
return DRUNKEN_SMASHED;
if (value >= 50)
return DRUNKEN_DRUNK;
if (value)
return DRUNKEN_TIPSY;
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;
SetUInt16Value(PLAYER_BYTES_3, 0, uint16(getGender()) | (m_drunk & 0xFFFE));
if (newDrunkValue < GetDrunkValue())
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
if (newDrunkenState >= DRUNKEN_DRUNK)
@ -1365,11 +1371,11 @@ void Player::Update(uint32 update_diff, uint32 p_time)
m_Last_tick = now;
}
if (m_drunk)
if (GetDrunkValue())
{
m_drunkTimer += update_diff;
if (m_drunkTimer > 10 * IN_MILLISECONDS)
if (m_drunkTimer > 9 * IN_MILLISECONDS)
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, 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
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_2, fields[10].GetUInt32());
m_drunk = fields[45].GetUInt16();
SetUInt16Value(PLAYER_BYTES_3, 0, (m_drunk & 0xFFFE) | gender);
SetByteValue(PLAYER_BYTES_3, 0, gender);
SetByteValue(PLAYER_BYTES_3, 1, fields[45].GetUInt8());
SetUInt32Value(PLAYER_FLAGS, fields[11].GetUInt32());
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
// calculate sobering. after 15 minutes logged out, the player will be sober again
float soberFactor;
if (time_diff > 15 * MINUTE)
soberFactor = 0;
else
soberFactor = 1 - time_diff / (15.0f * MINUTE);
uint16 newDrunkenValue = uint16(soberFactor * m_drunk);
SetDrunkValue(newDrunkenValue);
uint8 newDrunkValue = 0;
if (time_diff < uint32(GetDrunkValue()) * 9)
newDrunkValue = GetDrunkValue() - time_diff / 9;
SetDrunkValue(newDrunkValue);
m_cinematic = fields[18].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)
uberInsert.addUInt32(GetUInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX));
uberInsert.addUInt16(uint16(GetUInt32Value(PLAYER_BYTES_3) & 0xFFFE));
uberInsert.addUInt8(GetDrunkValue());
uberInsert.addUInt32(GetHealth());

View file

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

View file

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

View file

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

View file

@ -1,6 +1,6 @@
#ifndef __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_REALMD "required_c12484_02_realmd_account_access"
#endif // __REVISION_SQL_H__