diff --git a/src/common/service.h b/src/common/service.h index d6236ec..749637b 100644 --- a/src/common/service.h +++ b/src/common/service.h @@ -3,17 +3,19 @@ #define ENABLE_AUTODETECT_INTERNAL_IP #define ENABLE_PROXY_IP -#define _IMPROVED_PACKET_ENCRYPTION_ // 패킷 암호화 개선 +#define _IMPROVED_PACKET_ENCRYPTION_ // 패킷 암호화 개선 #define __PET_SYSTEM__ #define __UDP_BLOCK__ -#define FIX_HEADER_CG_MARK_LOGIN // Fix for syserr error header 100 (login phase does not handle this packet! header 100); -#define FIX_NEG_CMD_CORE_DOWNER // Fix core downer after negative command value (mobs, items, etc...) -#define FIX_NEG_HP // Fix negative HP value when dead -#define FIX_MESSENGER_ACTION_SYNC // Fix companion messenger updates when being deleted by a friend +#define FIX_HEADER_CG_MARK_LOGIN // Fix for syserr error header 100 (login phase does not handle this packet! header 100); +#define FIX_NEG_CMD_CORE_DOWNER // Fix core downer after negative command value (mobs, items, etc...) +#define FIX_NEG_HP // Fix negative HP value when dead +#define FIX_MESSENGER_ACTION_SYNC // Fix companion messenger updates when being deleted by a friend #define CHAR_SELECT_STATS_IMPROVEMENT // Improve stats values in character select screen #define CROSS_CHANNEL_FRIEND_REQUEST // Allow friend requests across different channels -#define FIX_REFRESH_SKILL_COOLDOWN // Fix cooldown display time on skill slots +#define FIX_REFRESH_SKILL_COOLDOWN // Fix cooldown display time on skill slots #define FIX_BOOK_READING_FOR_MAX_LEVEL // Disable experience point deduction for reading a book when in max level +#define FIX_BATTLE_INACTIVITY_TIMEOUT // by #tw1x1: Add battle mode inactivity timeout and reset to standing +#define __BL_LEVEL_FIX__ // Live character level updates #endif diff --git a/src/game/char.cpp b/src/game/char.cpp index b5f954d..e9bfaf2 100644 --- a/src/game/char.cpp +++ b/src/game/char.cpp @@ -361,6 +361,12 @@ void CHARACTER::Initialize() m_bIsLoadedAffect = false; cannot_dead = false; +#ifdef FIX_BATTLE_INACTIVITY_TIMEOUT + // tw1x1: POS_FIGHTING timer fix + m_dwLastCombatTime = 0; + // tw1x1: end +#endif + #ifdef __PET_SYSTEM__ m_petSystem = 0; m_bIsPet = false; @@ -2650,6 +2656,19 @@ bool CHARACTER::Sync(long x, long y) SetRotationToXY(x, y); SetXYZ(x, y, 0); +#ifdef TW1X1_TEST + m_posDest.x = m_posStart.x = x; + m_posDest.y = m_posStart.y = y; + + // If we were moving, stop movement state after a correction. + // Client will resend intent if it still wants to move. + if (IsState(m_stateMove)) + { + m_dwStateDuration = 0; + GotoState(m_stateIdle); + } +#endif + if (GetDungeon()) { // 던젼용 이벤트 속성 변화 @@ -4091,6 +4110,22 @@ void CHARACTER::UpdateStateMachine(DWORD dwPulse) if (IsDead()) return; +#ifdef FIX_BATTLE_INACTIVITY_TIMEOUT + // tw1x1: POS_FIGHTING timer fix + if (IsPC() && IsPosition(POS_FIGHTING)) + { + const DWORD now = get_dword_time(); + + // If we never set a combat time yet, set it now so timer can start. + if (m_dwLastCombatTime == 0) + m_dwLastCombatTime = now; + + if (now - m_dwLastCombatTime >= 10000) + SetVictim(NULL); // triggers battle_end() -> POS_STANDING + } + // tw1x1: end +#endif + Update(); m_dwNextStatePulse = dwPulse + m_dwStateDuration; } @@ -5907,7 +5942,11 @@ void CHARACTER::ResetPoint(int iLv) { BYTE bJob = GetJob(); +#if defined(__BL_LEVEL_FIX__) + PointChange(POINT_LEVEL, iLv - GetLevel(), false, true); +#else PointChange(POINT_LEVEL, iLv - GetLevel()); +#endif SetRealPoint(POINT_ST, JobInitialPoints[bJob].st); SetPoint(POINT_ST, GetRealPoint(POINT_ST)); diff --git a/src/game/char.h b/src/game/char.h index 21b7128..aa7f51c 100644 --- a/src/game/char.h +++ b/src/game/char.h @@ -2044,6 +2044,18 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider protected: int m_iLastPMPulse; int m_iPMCounter; + +#ifdef FIX_BATTLE_INACTIVITY_TIMEOUT + // tw1x1: POS_FIGHTING timer fix + public: + void EnterCombat(); + void UpdateLastCombatTime() { m_dwLastCombatTime = get_dword_time(); } + DWORD GetLastCombatTime() const { return m_dwLastCombatTime; } + + private: + DWORD m_dwLastCombatTime; + // tw1x1: end +#endif }; ESex GET_SEX(LPCHARACTER ch); diff --git a/src/game/char_battle.cpp b/src/game/char_battle.cpp index f991fb0..1d10bea 100644 --- a/src/game/char_battle.cpp +++ b/src/game/char_battle.cpp @@ -41,6 +41,7 @@ #include "DragonLair.h" #include #include + DWORD AdjustExpByLevel(const LPCHARACTER ch, const DWORD exp) { if (PLAYER_EXP_TABLE_MAX < ch->GetLevel()) @@ -208,8 +209,11 @@ bool CHARACTER::Attack(LPCHARACTER pkVictim, BYTE bType) pkVictim->SetSyncOwner(this); + // Always ensure the victim is in fighting state and has the inactivity timer running if (pkVictim->CanBeginFight()) + { pkVictim->BeginFight(this); + } int iRet; @@ -1608,12 +1612,29 @@ void CHARACTER::SendDamagePacket(LPCHARACTER pAttacker, int Damage, BYTE DamageF // true : dead // false : not dead yet // + +#ifdef FIX_BATTLE_INACTIVITY_TIMEOUT +// tw1x1: POS_FIGHTING timer fix +void CHARACTER::EnterCombat() +{ + if (!IsPC()) + return; + + if (!IsPosition(POS_FIGHTING)) + SetPosition(POS_FIGHTING); + + SetNextStatePulse(1); +} +// tw1x1: end +#endif + bool CHARACTER::Damage(LPCHARACTER pAttacker, int dam, EDamageType type) // returns true if dead { if (DAMAGE_TYPE_MAGIC == type) { dam = (int)((float)dam * (100 + (pAttacker->GetPoint(POINT_MAGIC_ATT_BONUS_PER) + pAttacker->GetPoint(POINT_MELEE_MAGIC_ATT_BONUS_PER))) / 100.f + 0.5f); } + if (GetRaceNum() == 5001) { bool bDropMoney = false; @@ -2295,6 +2316,26 @@ bool CHARACTER::Damage(LPCHARACTER pAttacker, int dam, EDamageType type) // retu if (GetHP() - dam <= 0) dam = GetHP(); #endif + +#ifdef FIX_BATTLE_INACTIVITY_TIMEOUT + // tw1x1: POS_FIGHTING timer fix + // REAL combat activity only: final damage > 0 + if (dam > 0) + { + // Victim received real damage + UpdateLastCombatTime(); + EnterCombat(); + + // Attacker dealt real damage + if (pAttacker) + { + pAttacker->UpdateLastCombatTime(); + pAttacker->EnterCombat(); + } + } + // tw1x1: end +#endif + PointChange(POINT_HP, -dam, false); } diff --git a/src/game/char_skill.cpp b/src/game/char_skill.cpp index 430fac6..5d39af6 100644 --- a/src/game/char_skill.cpp +++ b/src/game/char_skill.cpp @@ -2001,18 +2001,7 @@ int CHARACTER::ComputeSkill(DWORD dwVnum, LPCHARACTER pkVictim, BYTE bSkillLevel // 말을 타고있지만 스킬은 사용할 수 없는 상태라면 return if (false == bCanUseHorseSkill && true == IsRiding()) -#ifdef FIX_REFRESH_SKILL_COOLDOWN - { - const bool bToggleSkill = pkSk && IS_SET(pkSk->dwFlag, SKILL_FLAG_TOGGLE); - const bool bToggleActive = bToggleSkill ? (dwVnum == SKILL_COMBO ? m_bComboIndex != 0 : FindAffect(dwVnum) != nullptr) : false; - - // Allow only deactivation of already-active toggles (combo or other) while riding - if (!bToggleActive) - return BATTLE_NONE; - } -#else return BATTLE_NONE; -#endif if (IsPolymorphed()) return BATTLE_NONE; @@ -2023,14 +2012,7 @@ int CHARACTER::ComputeSkill(DWORD dwVnum, LPCHARACTER pkVictim, BYTE bSkillLevel if (!pkSk) return BATTLE_NONE; -#ifdef FIX_REFRESH_SKILL_COOLDOWN - const bool bIsToggleSkill = IS_SET(pkSk->dwFlag, SKILL_FLAG_TOGGLE); - const bool bToggleActive = bIsToggleSkill ? (dwVnum == SKILL_COMBO ? m_bComboIndex != 0 : FindAffect(dwVnum) != nullptr) : false; - - if (bCanUseHorseSkill && pkSk->dwType != SKILL_TYPE_HORSE && !(bIsToggleSkill && bToggleActive)) -#else if (bCanUseHorseSkill && pkSk->dwType != SKILL_TYPE_HORSE) -#endif return BATTLE_NONE; if (!bCanUseHorseSkill && pkSk->dwType == SKILL_TYPE_HORSE) @@ -2509,18 +2491,7 @@ bool CHARACTER::UseSkill(DWORD dwVnum, LPCHARACTER pkVictim, bool bUseGrandMaste // 말을 타고있지만 스킬은 사용할 수 없는 상태라면 return false if (false == bCanUseHorseSkill && true == IsRiding()) -#ifdef FIX_REFRESH_SKILL_COOLDOWN - { - const bool bToggleSkill = pkSk && IS_SET(pkSk->dwFlag, SKILL_FLAG_TOGGLE); - const bool bToggleActive = bToggleSkill ? (dwVnum == SKILL_COMBO ? m_bComboIndex != 0 : FindAffect(dwVnum) != nullptr) : false; - - // Allow only deactivation of already-active toggles (combo or other) while riding - if (!bToggleActive) - return false; - } -#else return false; -#endif // CSkillProto * pkSk = CSkillManager::instance().Get(dwVnum); sys_log(0, "%s: USE_SKILL: %d pkVictim %p", GetName(), dwVnum, get_pointer(pkVictim)); @@ -2528,14 +2499,16 @@ bool CHARACTER::UseSkill(DWORD dwVnum, LPCHARACTER pkVictim, bool bUseGrandMaste if (!pkSk) return false; -#ifdef FIX_REFRESH_SKILL_COOLDOWN - const bool bIsToggleSkill = IS_SET(pkSk->dwFlag, SKILL_FLAG_TOGGLE); - const bool bToggleActive = bIsToggleSkill ? (dwVnum == SKILL_COMBO ? m_bComboIndex != 0 : FindAffect(dwVnum) != nullptr) : false; - - if (bCanUseHorseSkill && pkSk->dwType != SKILL_TYPE_HORSE && !(bIsToggleSkill && bToggleActive)) -#else - if (bCanUseHorseSkill && pkSk->dwType != SKILL_TYPE_HORSE) +#ifdef FIX_BATTLE_INACTIVITY_TIMEOUT + // tw1x1: POS_FIGHTING timer fix + if (IsPC() && IS_SET(pkSk->dwFlag, SKILL_FLAG_ATTACK)) + { + EnterCombat(); + } + // tw1x1: end #endif + + if (bCanUseHorseSkill && pkSk->dwType != SKILL_TYPE_HORSE) return BATTLE_NONE; if (!bCanUseHorseSkill && pkSk->dwType == SKILL_TYPE_HORSE) @@ -2695,7 +2668,15 @@ bool CHARACTER::UseSkill(DWORD dwVnum, LPCHARACTER pkVictim, bool bUseGrandMaste ResetChainLightningIndex(); AddChainLightningExcept(pkVictim); } - + +#ifdef FIX_BATTLE_INACTIVITY_TIMEOUT + // tw1x1: POS_FIGHTING timer fix + if (IsPC() && IS_SET(pkSk->dwFlag, SKILL_FLAG_ATTACK)) + { + EnterCombat(); + } + // tw1x1: end +#endif if (IS_SET(pkSk->dwFlag, SKILL_FLAG_SELFONLY)) ComputeSkill(dwVnum, this); diff --git a/src/game/questlua_pc.cpp b/src/game/questlua_pc.cpp index 6f7f7d2..ae48438 100644 --- a/src/game/questlua_pc.cpp +++ b/src/game/questlua_pc.cpp @@ -864,7 +864,11 @@ namespace quest ch->PointChange(POINT_SUB_SKILL, newLevel < 10 ? 0 : newLevel - MAX(ch->GetLevel(), 9)); ch->PointChange(POINT_STAT, ((MINMAX(1, newLevel, 90) - ch->GetLevel()) * 3) + ch->GetPoint(POINT_LEVEL_STEP)); //레벨 +#if defined(__BL_LEVEL_FIX__) + ch->PointChange(POINT_LEVEL, newLevel - ch->GetLevel(), false, true); +#else ch->PointChange(POINT_LEVEL, newLevel - ch->GetLevel()); +#endif //HP, SP ch->SetRandomHP((newLevel - 1) * number(JobInitialPoints[ch->GetJob()].hp_per_lv_begin, JobInitialPoints[ch->GetJob()].hp_per_lv_end)); ch->SetRandomSP((newLevel - 1) * number(JobInitialPoints[ch->GetJob()].sp_per_lv_begin, JobInitialPoints[ch->GetJob()].sp_per_lv_end));