KnightOnline
KnightOnline copied to clipboard
CUser::Regene() bugs
CUser::Regene() (used on respawn) is a bit outdated and buggy. Ignoring the functionality that doesn't exist, the 2 main problems with it right now are that:
- The positioning logic is outdated and can fall through to not even finding a position (e.g. when dying in Moradon).
- Doesn't restore HP. This is apparently just commented out; it shouldn't be.
- Position Logic. As I looked into it, the logic for moradon is just this
float x = (float) (myrand(0, 400) / 100.0f);
float z = (float) (myrand(0, 400) / 100.0f);
if (x < 2.5f)
x += 1.5f;
if (z < 2.5f)
z += 1.5f;
Do you have description how it should work for moradon?
- The HpChange is also commented out for BattleZone:
/*
m_bResHpType = USER_STANDING;
HpChange( m_iMaxHp );
KickOutZoneUser(); // Go back to your own zone!
return;
*/
How do we wanna go on with this one? As I remember it we should enable standing and hpchange, or?
The official implementation for 1.298:
void __thiscall CUser::Regene(CUser *this, char *pBuf, int magicid)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
memset(logstr, 0, sizeof(logstr));
if ( this->m_bResHpType == 3 )
{
if ( this->m_pUserData->m_sHp > 0 )
CUser::HpChange(this, -this->m_iMaxHp, 0, 0);
if ( this->m_PetSystem.m_sPetID > 0 )
{
memset(ai_send_buff, 0, sizeof(ai_send_buff));
regene_index = this->m_Sid;
ai_send_buff[0] = AG_USER_PET_SYSTEM;
ai_send_buff[1] = 1;
ai_send_buff[2] = 1;
ai_send_buff[3] = PET_USERGUARD_COMMAND_DESTROY;
memcpy(&ai_send_buff[4], ®ene_index, 2u);
LOWORD(v4) = this->m_PetSystem.m_sPetID;
regene_index = v4;
memcpy(&ai_send_buff[6], ®ene_index, 2u);
CEbenezerDlg::Send_AIServer(this->m_pMain, this->m_pUserData->m_bZone, ai_send_buff, 8u);
this->m_PetSystem.m_sPetID = -1;
}
CUser::InitType3(this);
CUser::InitType4(this);
CUser::InitType6(this);
CUser::InitType9(this, 1);
CUser::InitType9(this, 2);
CUser::InitType9(this, 3);
CUser::UserInOut(this, INOUT_OUT);
CTime::GetTickCount(a1);
regene_type = *pBuf;
regene_type = *pBuf;
if ( regene_type != 1 )
{
if ( regene_type == 2 )
{
m_pUserData = this->m_pUserData;
magicid = 490041;
if ( (unsigned __int8)CUser::ItemCountChange(this, 379006000, 1, 3 * m_pUserData->m_bLevel, 0) < 2u )
{
memset(logstr, 0, sizeof(logstr));
_snprintf(
logstr,
256u,
"$$ UserRegene Fail 2 - acid=%s, charid=%s, magicid=%d, type=%d, level=%d, zone=%d $$",
this->m_pUserData->m_Accountid,
this->m_pUserData,
490041,
this->m_bResHpType,
this->m_pUserData->m_bLevel,
this->m_pUserData->m_bZone);
goto write_event_log;
}
if ( this->m_pUserData->m_bLevel <= 5u )
return;
}
else
{
regene_type = 1;
}
}
if ( !CSTLMap<_HOME_INFO>::GetData(&this->m_pMain->m_HomeArray, this->m_pUserData->m_bNation) )
{
memset(logstr, 0, sizeof(logstr));
_snprintf(
logstr,
256u,
"$$ UserRegene Fail 3 - acid=%s, charid=%s, magicid=%d, type=%d, level=%d, zone=%d $$",
this->m_pUserData->m_Accountid,
this->m_pUserData,
magicid,
this->m_bResHpType,
this->m_pUserData->m_bLevel,
this->m_pUserData->m_bZone);
goto write_event_log;
}
memset(send_buff, 0, sizeof(send_buff));
m_iZoneIndex = this->m_iZoneIndex;
if ( m_iZoneIndex < 0
|| ((Myfirst = this->m_pMain->m_ZoneArray._Myfirst) != 0 ? (v9 = this->m_pMain->m_ZoneArray._Mylast - Myfirst) : (v9 = 0),
m_iZoneIndex >= v9) )
{
memset(logstr, 0, sizeof(logstr));
_snprintf(
logstr,
256u,
"$$ UserRegene Fail 4 - acid=%s, charid=%s, magicid=%d, type=%d, level=%d, zone=%d $$",
this->m_pUserData->m_Accountid,
this->m_pUserData,
magicid,
this->m_bResHpType,
this->m_pUserData->m_bLevel,
this->m_pUserData->m_bZone);
goto write_event_log;
}
*(float *)®ene_index = COERCE_FLOAT(myrand(0, 400));
*(float *)&a1[1] = (double)regene_index * 0.0099999998;
*(float *)®ene_index = (double)myrand(0, 400) * 0.0099999998;
if ( v11 )
*(float *)&a1[1] = *(float *)&a1[1] + 1.5;
if ( *(float *)®ene_index < 2.5 )
*(float *)®ene_index = *(float *)®ene_index + 1.5;
EnterCriticalSection(&g_region_critical);
pEvent = CSTLMap<_OBJECT_EVENT>::GetData(
&this->m_pMain->m_ZoneArray._Myfirst[this->m_iZoneIndex]->m_ObjectEventArray,
this->m_pUserData->m_sBind);
LeaveCriticalSection(&g_region_critical);
if ( magicid )
{
after_magicid_check:
m_pUserData = this->m_pUserData;
send_buff[0] = WIZ_REGENE;
pEvent = (_OBJECT_EVENT *)(10 * (__int64)m_pUserData->m_curx);
memcpy(&send_buff[1], &pEvent, 2u);
pEvent = (_OBJECT_EVENT *)(10 * (__int64)this->m_pUserData->m_curz);
memcpy(&send_buff[3], &pEvent, 2u);
pEvent = (_OBJECT_EVENT *)(10 * (__int64)this->m_pUserData->m_cury);
memcpy(&send_buff[5], &pEvent, 2u);
CIOCPSocket2::Send(this, send_buff, 7, 0);
if ( magicid <= 0 )
{
m_iMaxHp = this->m_iMaxHp;
this->m_bResHpType = 1;
CUser::HpChange(this, m_iMaxHp, 0, 0);
this->m_bRegeneType = 0;
}
else
{
pType = CSTLMap<_MAGIC_TYPE5>::GetData(&this->m_pMain->m_Magictype5Array.__vftable, magicid);
if ( !pType )
{
memset(logstr, 0, sizeof(logstr));
_snprintf(
logstr,
256u,
"$$ UserRegene Fail 5 - acid=%s, charid=%s, magicid=%d, type=%d, level=%d, zone=%d $$",
this->m_pUserData->m_Accountid,
this->m_pUserData,
magicid,
this->m_bResHpType,
this->m_pUserData->m_bLevel,
this->m_pUserData->m_bZone);
goto write_event_log;
}
v36 = this->m_iMaxHp;
this->m_bResHpType = 1;
CUser::HpChange(this, v36, 0, 0);
CUser::MSpChange(this, -this->m_iMaxMp);
if ( regene_type == 1 )
{
CUser::ExpChange(this, this->m_iLostExp * pType->bExpRecover / 100, 0, 0);
CUser::DeathLogToAgent(this, this->m_Sid, this->m_Sid, this->m_iLostExp * pType->bExpRecover / 100);
}
this->m_bRegeneType = 1;
}
v31 = TimeGet();
v32 = this->m_pUserData;
this->m_sWhoKilledMe = -1;
this->m_fLastRegeneTime = v31;
this->m_iLostExp = 0;
v32->m_bCity = 0;
if ( this->m_bAbnormalType != 4 )
{
memset(send_buff, 0, sizeof(send_buff));
magicid = this->m_Sid;
send_buff[0] = AG_USER_REGENE;
memcpy(&send_buff[1], &magicid, 2u);
v33 = this->m_pUserData;
LOWORD(v33) = v33->m_sHp;
magicid = (int)v33;
memcpy(&send_buff[3], &magicid, 2u);
CEbenezerDlg::Send_AIServer(this->m_pMain, this->m_pUserData->m_bZone, send_buff, 5u);
}
memset(send_buff, 0, sizeof(send_buff));
wsprintfA(
send_buff,
"<------ User Regene ,, nid=%d, name=%s, type=%d ******",
this->m_Sid,
this->m_pUserData->m_id,
this->m_bResHpType);
memset(send_buff, 0, sizeof(send_buff));
v34 = this->m_pUserData;
this->m_RegionX = (__int64)(v34->m_curx * 0.020833334);
this->m_RegionZ = (__int64)(v34->m_curz * 0.020833334);
CUser::UserInOut(this, INOUT_RESPAWN);
CEbenezerDlg::UserInOutForMe(this->m_pMain, this);
CEbenezerDlg::NpcInOutForMe(this->m_pMain, this);
CUser::BlinkStart(this);
CUser::ItemMallMagicRecast(this, 1);
CUser::SetSlotItemValue(this);
CUser::SetUserAbility(this, 0);
CUser::Send2AI_UserUpdateInfo(this);
CUser::SendMonsterFriendlyFlagToAI(this, 0);
memset(send_buff, 0, sizeof(send_buff));
CUser::StateChangeServerDirect(this, STATE_CHANGE_STEALTH, this->m_byInvisibilityType);
memset(send_buff, 0, sizeof(send_buff));
strcpy(send_buff, "`");
magicid = 0;
memcpy(&send_buff[2], &magicid, 2u);
CIOCPSocket2::Send(this, send_buff, 4, 0);
if ( this->m_sPartyIndex != -1 )
{
if ( this->m_bType3Flag )
goto LABEL_89;
CUser::SendPartyUserStatusChange(this, USER_STATUS_DOT, USER_STATUS_CURE);
}
if ( !this->m_bType3Flag )
CUser::SendUserStatusChange(this, USER_STATUS_DOT, USER_STATUS_CURE);
LABEL_89:
if ( this->m_sPartyIndex != -1 )
{
if ( this->m_bType4Flag )
{
LABEL_94:
v35 = this->m_pUserData;
this->m_fWill_x = v35->m_curx;
this->m_fWill_z = v35->m_curz;
this->m_fWill_y = v35->m_cury;
return;
}
CUser::SendPartyUserStatusChange(this, USER_STATUS_POISON, USER_STATUS_CURE);
CUser::SendPartyUserStatusChange(this, USER_STATUS_SPEED, USER_STATUS_CURE);
}
if ( !this->m_bType4Flag )
{
CUser::SendUserStatusChange(this, USER_STATUS_POISON, USER_STATUS_CURE);
CUser::SendUserStatusChange(this, USER_STATUS_SPEED, USER_STATUS_CURE);
}
goto LABEL_94;
}
m_pUserData = this->m_pUserData;
bZone = m_pUserData->m_bZone;
v12 = bZone;
if ( bZone == ZONE_ESLANT_KARUS || bZone == ZONE_ESLANT_ELMORAD )
{
if ( m_pUserData->m_bLevel >= 60u )
goto skip_to_bind_point_check;
goto kickout_and_skip_to_bind_point_check;
}
if ( bZone == ZONE_FRONTIER )
{
if ( this->m_pMain->m_byNationID != 3 )
{
if ( m_pUserData->m_bLevel < 30u )
CUser::KickOutZoneUser(this, 1, 0);
if ( this->m_pMain->m_byNationID != 1 )
goto skip_to_bind_point_check;
v14 = this->m_pUserData->m_iLoyalty <= 0;
LABEL_41:
if ( v14 )
goto LABEL_42;
skip_to_bind_point_check:
v15 = pEvent;
if ( pEvent && pEvent->byLife == 1 )
{
v17 = *(float *)&a1[1] + pEvent->fPosX;
v18 = this->m_pUserData;
this->m_fWill_x = v17;
v18->m_curx = v17;
v16 = *(float *)®ene_index + v15->fPosZ;
this->m_fWill_z = v16;
}
else
{
v19 = this->m_pUserData;
m_bZone = v19->m_bZone;
if ( m_bZone == ZONE_DELOS )
{
p_m_KnightsSiegeWar = &this->m_pMain->m_KnightsSiegeWar;
*(float *)®ene_index = 0.0;
CKnightsSiegeWar::GetRegenePosition(p_m_KnightsSiegeWar, &vPos, this, ®ene_index, 0);
if ( *(float *)®ene_index == 0.0 )
{
CUser::KickOutZoneUser(this, 1, 21);
}
else
{
this->m_pUserData->m_curx = vPos.x;
this->m_pUserData->m_curz = vPos.z;
}
LABEL_72:
v28 = this->m_pUserData->m_bZone;
if ( v28 >= ZONE_PRIVATE_ARENA_1 && v28 <= ZONE_PRIVATE_ARENA_6 )
{
m_Sid = this->m_Sid;
this->m_byRoomParticipationType = 2;
CUser::PartyRemove(this, m_Sid);
}
goto after_magicid_check;
}
m_pMain = this->m_pMain;
if ( m_pMain->m_byBattleOpen != NATION_BATTLE
|| (!m_pMain->m_byKarusOpenFlag || v19->m_bNation != 1)
&& (!m_pMain->m_byElmoradOpenFlag || v19->m_bNation != 2)
|| m_bZone >= (ZONE_CASTLE_ELMORAD|ZONE_CASTLE_LUFERSON) )
{
goto LABEL_70;
}
v24 = myrand(0, 9000);
v25 = this->m_pUserData;
*(float *)®ene_index = 0.0;
ZoneIndex = CEbenezerDlg::GetZoneIndex(this->m_pMain, v25->m_bNation);
if ( v24 >= 0 )
{
if ( v24 >= 3000 )
{
if ( v24 >= 6000 )
{
if ( v24 < 9001 )
regene_index = 2;
}
else
{
regene_index = 1;
}
}
else
{
*(float *)®ene_index = 0.0;
}
}
Data = CSTLMap<_REGENE_EVENT>::GetData(
&this->m_pMain->m_ZoneArray._Myfirst[ZoneIndex]->m_ObjectRegeneArray,
regene_index);
v27 = Data;
if ( Data )
{
pEvent = (_OBJECT_EVENT *)myrand(0, (__int64)Data->fRegeneAreaX);
this->m_pUserData->m_curx = (double)(int)pEvent + v27->fRegenePosX;
pEvent = (_OBJECT_EVENT *)myrand(0, (__int64)v27->fRegeneAreaZ);
v16 = (double)(int)pEvent + v27->fRegenePosZ;
}
else
{
LABEL_70:
pEvent = (_OBJECT_EVENT *)CUser::GetStartPosition((int)this, 1);
this->m_pUserData->m_curx = (float)(int)pEvent;
pEvent = (_OBJECT_EVENT *)CUser::GetStartPosition((int)this, 2);
v16 = (double)(int)pEvent;
}
}
this->m_pUserData->m_curz = v16;
this->m_pUserData->m_cury = 0.0;
goto LABEL_72;
}
}
else
{
v12 = bZone;
if ( bZone / 100 != 1 && (bZone == m_pUserData->m_bNation || bZone >= (ZONE_CASTLE_ELMORAD|ZONE_CASTLE_LUFERSON)) )
{
LABEL_43:
if ( v12 != ZONE_FORGOTTEN_TEMPLE )
goto skip_to_bind_point_check;
kickout_and_skip_to_bind_point_check:
CUser::KickOutZoneUser(this, 1, 21);
goto skip_to_bind_point_check;
}
}
if ( this->m_pMain->m_byNationID == 3 )
{
if ( m_pUserData->m_bLevel < 30u )
{
LABEL_42:
CUser::KickOutZoneUser(this, 1, 0);
goto skip_to_bind_point_check;
}
v14 = m_pUserData->m_iLoyalty <= 0;
goto LABEL_41;
}
goto LABEL_43;
}
memset(logstr, 0, sizeof(logstr));
_snprintf(
logstr,
256u,
"$$ UserRegene Fail 1 - acid=%s, charid=%s, magicid=%d, type=%d, zone=%d $$",
this->m_pUserData->m_Accountid,
this->m_pUserData->m_id,
magicid,
this->m_bResHpType,
this->m_pUserData->m_bZone);
write_event_log:
CEbenezerDlg::WriteEventLog(this->m_pMain, logstr);
}