320 lines
11 KiB
C++
320 lines
11 KiB
C++
#include "stdafx.h"
|
|
#include "UserAI.h"
|
|
#include "Logger.h"
|
|
#include "RadarDllWnd.h"
|
|
//
|
|
|
|
UserAI::UserAI()
|
|
{
|
|
m_last_npc_html = NULL;
|
|
clear();
|
|
}
|
|
|
|
UserAI::~UserAI()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
void UserAI::clear()
|
|
{
|
|
usr.clear();
|
|
inv.clear();
|
|
buffs.clear();
|
|
party.clear();
|
|
healItems.clear();
|
|
invisGM.clear();
|
|
cfgQuickTarg.clear();
|
|
targetManager.clear();
|
|
folAsiCfg.clear();
|
|
//
|
|
state = UAI_IDLE;
|
|
//
|
|
hThread = NULL;
|
|
dwThreadID = 0;
|
|
// heal items
|
|
healItems.enableHealHP = healItems.enableHealMP = healItems.enableHealCP = true;
|
|
// offparty bd, sws
|
|
offBDSWS_nextBDInvTime = offBDSWS_nextSWSInvTime = offBDSWS_nextBDDisTime = offBDSWS_nextSWSDisTime = 0;
|
|
offBD_inrange = offSWS_inrange = false;
|
|
// sound alerts
|
|
soundAlert_enabled = true;
|
|
soundAlert_fileNameCritical[0] = soundAlert_fileNameWarning[0] = soundAlert_fileNameInfo[0] = 0;
|
|
soundAlert_alertOnClanWar = 0; // 0 - none, 1 - info, 2 - warning, 3 - critical
|
|
soundAlert_alertOnTargeted = 0;
|
|
soundAlert_alertOnInvisGM = 0;
|
|
soundAlert_noPartyTargetAlert = soundAlert_noClanTargetAlert = 1;
|
|
soundAlert_screenMessage = 0;
|
|
// follow / asi
|
|
m_last_follow_time_msec = 0;
|
|
m_follow_oid = 0;
|
|
m_assist_oid = 0;
|
|
m_last_assist_time_msec = 0;
|
|
// npc html
|
|
m_last_npc_html_npcOid = 0;
|
|
if( m_last_npc_html )
|
|
{
|
|
free( m_last_npc_html );
|
|
m_last_npc_html = NULL;
|
|
}
|
|
}
|
|
|
|
void UserAI::userLogout()
|
|
{
|
|
usr.clear();
|
|
inv.clear();
|
|
buffs.clear();
|
|
party.clear();
|
|
healItems.clear();
|
|
invisGM.clear();
|
|
cfgQuickTarg.clear();
|
|
targetManager.clear();
|
|
folAsiCfg.clear();
|
|
m_follow_oid = 0;
|
|
m_assist_oid = 0;
|
|
//
|
|
state = UAI_IDLE;
|
|
//
|
|
CharArray_DeleteAll();
|
|
NpcArray_DeleteAll();
|
|
GIArray::getInstance()->DeleteAll();
|
|
log_error( LOG_USERAI, "UserAI: Logout OK, User logged out (notified)\n" );
|
|
RadarWnd_ForceUpdateCharsList();
|
|
RadarWnd_ForceUpdateNpcsList();
|
|
RadarWnd_UpdateChecksState();
|
|
}
|
|
|
|
void UserAI::init()
|
|
{
|
|
clear();
|
|
// load all config
|
|
healItems.LoadFromFile( "L2Detect_healItems.ini" );
|
|
off_BD_SWS.readFromFile( "L2Detect_offp_BDSWS.ini" );
|
|
setOffpartyBDSWS_Enable( off_BD_SWS.allEnabled ); // process...
|
|
cfgQuickTarg.loadFromFile( "L2Detect_quickTarg.ini" );
|
|
targetManager.clear();
|
|
loadSoundAlertsCfgFromFile( "L2Detect_soundAlerts.ini" );
|
|
folAsiCfg.loadFromFile( "L2Detect_folAsi.ini" );
|
|
// force radar window to set all checks from our confg
|
|
RadarWnd_UpdateChecksState();
|
|
}
|
|
|
|
void UserAI::notifyEvent( int event_id )
|
|
{
|
|
switch( event_id )
|
|
{
|
|
case UAI_EVENT_START:
|
|
{
|
|
log_error( LOG_USERAI, "UserAI::notifyEvent(): START\n" );
|
|
if( hThread == NULL )
|
|
{
|
|
dwThreadID = 0;
|
|
hThread = (HANDLE)_beginthreadex( NULL, 0,
|
|
(unsigned int (__stdcall *)(void *))UserAIThread, (void *)this, 0,
|
|
(unsigned int *)&dwThreadID );
|
|
if( hThread )
|
|
log_error( LOG_USERAI, "UserAI::notifyEvent(): START OK %u\n", dwThreadID );
|
|
else
|
|
log_error( LOG_ERROR, "UserAI::notifyEvent(): START ERROR %d\n", GetLastError() );
|
|
}
|
|
else
|
|
log_error( LOG_ERROR, "UserAI::notifyEvent(): START: already running\n" );
|
|
} break;
|
|
case UAI_EVENT_STOP:
|
|
{
|
|
log_error( LOG_USERAI, "UserAI::notifyEvent(): STOPPING %u...\n", dwThreadID );
|
|
if( hThread != NULL )
|
|
{
|
|
if( !PostThreadMessage( dwThreadID, WM_CLOSE, 0, 0 ) )
|
|
{
|
|
log_error( LOG_ERROR, "UserAI::notifyEvent(): STOP: PostThreadMessage() error %u\n",
|
|
(unsigned int)GetLastError );
|
|
return;
|
|
}
|
|
Sleep( 100 );
|
|
while( hThread )
|
|
{
|
|
log_error_np( LOG_OK, "." );
|
|
Sleep( 250 );
|
|
}
|
|
log_error( LOG_USERAI, "\nUserAI::notifyEvent(): STOP WAIT OK\n" );
|
|
}
|
|
else
|
|
log_error( LOG_ERROR, "UserAI::notifyEvent(): STOP: not running\n" );
|
|
} break;
|
|
}
|
|
}
|
|
|
|
void UserAI::notifyEventPacket( int event_id, const unsigned char *bytes, unsigned int length )
|
|
{
|
|
if( !bytes || (length<1) ) return;
|
|
L2GamePacket *p = new L2GamePacket( bytes, length );
|
|
if( !p ) return;
|
|
#ifdef _DEBUG
|
|
BOOL ret = PostThreadMessage( dwThreadID, WM_KEYDOWN, event_id, (LPARAM)p );
|
|
if( !ret )
|
|
{
|
|
DWORD le = GetLastError();
|
|
ErrorLogger_LogLastError( "UserAI::notifyEventPacket(): PostThreadMessage() failed", le );
|
|
log_error( LOG_ERROR, "tid = %u\n", dwThreadID );
|
|
}
|
|
#else
|
|
PostThreadMessage( dwThreadID, WM_KEYDOWN, event_id, (LPARAM)p );
|
|
#endif
|
|
}
|
|
|
|
void UserAI::notifyUIKeyUp( int vkey )
|
|
{
|
|
PostThreadMessage( dwThreadID, WM_KEYUP, (WPARAM)vkey, (LPARAM)0 );
|
|
}
|
|
|
|
DWORD WINAPI UserAI::UserAIThread( LPVOID lpParam )
|
|
{
|
|
class UserAI *cls = (class UserAI *)lpParam;
|
|
if( !cls ) return 12345;
|
|
MSG msg;
|
|
// create thread's message queue
|
|
PeekMessage( &msg, NULL, WM_USER, WM_USER, PM_NOREMOVE );
|
|
// now message queue for this thread is created
|
|
log_error( LOG_USERAI, "UserAIThread(): started, created message queue\n" );
|
|
//
|
|
int shouldExit = 0;
|
|
int was_message = 0;
|
|
do
|
|
{
|
|
was_message = 0;
|
|
if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
|
|
{
|
|
was_message = 1;
|
|
//log_error( LOG_OK, "UserAIThread(): GotMessage %u\n", msg.message );
|
|
switch( msg.message )
|
|
{
|
|
//case WM_CREATE: { /*log_error( LOG_DEBUG, "UserAIThread(): WM_CREATE\n" );*/ } break;
|
|
case WM_CLOSE: { /*log_error( LOG_DEBUG, "UserAIThread(): WM_CLOSE\n" );*/ shouldExit = 1; } break;
|
|
case WM_KEYDOWN: UAI_ParsePacket( cls, msg.wParam, msg.lParam ); break;
|
|
case WM_KEYUP: cls->UAI_handle_keyboard( (int)msg.wParam ); break;
|
|
}
|
|
}
|
|
if( shouldExit ) break;
|
|
if( !was_message ) Sleep( 100 );
|
|
|
|
// process all L2Character moves in visible area, also process user move
|
|
// process buff ticks, skill reuses
|
|
UAI_ProcessWorld( cls );
|
|
|
|
// check HP,MP,CP
|
|
if( cls->healItems.enableHealHP ) UAI_CheckHP( cls );
|
|
if( cls->healItems.enableHealMP ) UAI_CheckMP( cls );
|
|
if( cls->healItems.enableHealCP ) UAI_CheckCP( cls );
|
|
|
|
// check if enabled offparty bd, sws invite/dismiss
|
|
if( cls->off_BD_SWS.allEnabled ) UAI_ProcessOffpartyBDSWS( cls );
|
|
|
|
// process follow/assist
|
|
if( cls->folAsiCfg.m_follow_enable ) UAI_ProcessFollow( cls );
|
|
if( cls->folAsiCfg.m_assist_enable ) UAI_ProcessAssist( cls );
|
|
}
|
|
while( !shouldExit );
|
|
//
|
|
log_error( LOG_USERAI, "UserAIThread(): ending\n" );
|
|
//
|
|
CloseHandle( cls->hThread );
|
|
cls->hThread = NULL;
|
|
cls->dwThreadID = 0;
|
|
return 0;
|
|
}
|
|
|
|
void UserAI::UAI_ParsePacket( class UserAI *cls, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
if( lParam == 0 ) return;
|
|
L2GamePacket *p = (L2GamePacket *)lParam;
|
|
int event_id = (int)wParam;
|
|
//
|
|
try
|
|
{
|
|
//
|
|
switch( event_id )
|
|
{
|
|
case UAI_PEVENT_USERINFO: cls->usr.parse_UserInfo( p ); break;
|
|
case UAI_PEVENT_STATUSUPDATE: cls->UAI_Parse_StatusUpdate( cls, p ); break;
|
|
case UAI_PEVENT_ITEMLIST: cls->inv.parse_ItemList( p ); break;
|
|
case UAI_PEVENT_INVENTORYUPDATE: cls->inv.parse_InventoryUpdate( p ); break;
|
|
case UAI_PEVENT_MOVETOLOCATION: cls->UAI_Parse_MoveToLocation( cls, p ); break;
|
|
case UAI_PEVENT_STOPMOVE: cls->UAI_Parse_StopMove( cls, p ); break;
|
|
case UAI_PEVENT_TELEPORTTOLOCATION: cls->UAI_Parse_TeleportToLocation( cls, p ); break;
|
|
case UAI_PEVENT_PLEDGERECEIVEWARLIST: cls->warList.parse_PledgeReceiveWarList( p ); break;
|
|
case UAI_PEVENT_NPCINFO: cls->UAI_Parse_NpcInfo( cls, p ); break;
|
|
case UAI_PEVENT_DELETEOBJECT: cls->UAI_Parse_DeleteObject( cls, p ); break;
|
|
case UAI_PEVENT_CHARINFO: cls->UAI_Parse_CharInfo( cls, p ); break;
|
|
case UAI_PEVENT_TARGETSELECTED: cls->UAI_Parse_TargetSelected( cls, p ); break;
|
|
case UAI_PEVENT_TARGETUNSELECTED: cls->UAI_Parse_TargetUnselected( cls, p ); break;
|
|
case UAI_PEVENT_RELATIONCHANGED: cls->UAI_Parse_RelationChanged( cls, p ); break;
|
|
case UAI_PEVENT_MYTARGETSELECTED: cls->UAI_Parse_MyTargetSelected( cls, p ); break;
|
|
// party
|
|
case UAI_PEVENT_PARTYADD: cls->UAI_Parse_PartySmallWindowAdd( cls, p ); break;
|
|
case UAI_PEVENT_PARTYALL: cls->UAI_Parse_PartySmallWindowAll( cls, p ); break;
|
|
case UAI_PEVENT_PARTYDEL: cls->UAI_Parse_PartySmallWindowDelete( cls, p ); break;
|
|
case UAI_PEVENT_PARTYDELALL: cls->UAI_Parse_PartySmallWindowDeleteAll( cls, p ); break;
|
|
case UAI_PEVENT_PARTYUPDATE: cls->UAI_Parse_PartySmallWindowUpdate( cls, p ); break;
|
|
case UAI_PEVENT_PARTYSPELLED: cls->UAI_Parse_PartySpelled( cls, p ); break;
|
|
// die/revive
|
|
case UAI_PEVENT_DIE: cls->UAI_Parse_Die( cls, p ); break;
|
|
case UAI_PEVENT_REVIVE: cls->UAI_Parse_Revive( cls, p ); break;
|
|
// buffs
|
|
case UAI_PEVENT_ABNORMALSTATUSUPDATE: cls->UAI_Parse_AbnormalStatusUpdate( cls, p ); break;
|
|
case UAI_PEVENT_SHORTBUFFSTATUSUPDATE: cls->UAI_Parse_ShortBuffStatusUpdate( cls, p ); break;
|
|
// skills
|
|
case UAI_PEVENT_SETUPGAUGE: cls->UAI_Parse_SetupGauge( cls, p ); break;
|
|
case UAI_PEVENT_SKILLLIST: cls->UAI_Parse_SkillList( cls, p ); break;
|
|
case UAI_PEVENT_SKILLCOOLTIME: cls->UAI_Parse_SkillCoolTime( cls, p ); break;
|
|
case UAI_PEVENT_MAGICSKILLUSE: cls->UAI_Parse_MagicSkillUse( cls, p ); break;
|
|
case UAI_PEVENT_MAGICSKILLCANCELLED: cls->UAI_Parse_MagicSkillCancelled( cls, p ); break;
|
|
// items
|
|
case UAI_PEVENT_DROPITEM: cls->UAI_Parse_DropItem( cls, p ); break;
|
|
case UAI_PEVENT_SPAWNITEM: cls->UAI_Parse_SpawnItem( cls, p ); break;
|
|
}
|
|
//
|
|
} // try
|
|
catch( L2P_Exception& e )
|
|
{
|
|
log_error( LOG_ERROR, "L2P_Exception in UAI_ParsePacket (event_id = %d):\n%s\n",
|
|
event_id, e.what() );
|
|
}
|
|
//
|
|
delete p;
|
|
}
|
|
|
|
void UserAI::setHealItemsTable( const HealItemsTable *other )
|
|
{
|
|
if( !other ) return;
|
|
// possible decision - reload table from saved file
|
|
//this->healItems.LoadFromFile( "L2Detect_healItems.ini" );
|
|
// other way - full memcpy :)
|
|
memcpy( (void *)(&(this->healItems)), (const void *)other, sizeof(class HealItemsTable) );
|
|
}
|
|
|
|
void UserAI::setOffpartyBDSWS_Config( const UserAI_OffpartyBDSWS *other )
|
|
{
|
|
if( !other ) return;
|
|
memcpy( (void *)(&(this->off_BD_SWS)), (const void *)other, sizeof(class UserAI_OffpartyBDSWS) );
|
|
}
|
|
|
|
void UserAI::setOffpartyBDSWS_Enable( int bEnable )
|
|
{
|
|
if( (bEnable != 0) /*&& (this->off_BD_SWS.allEnabled == 0)*/ )
|
|
{
|
|
this->off_BD_SWS.allEnabled = 1;
|
|
this->offBDSWS_nextBDInvTime = GetTickCount() + 500; // ~ current time
|
|
this->offBDSWS_nextSWSInvTime = this->offBDSWS_nextBDInvTime;
|
|
// next dismiss time = next invite time + dismiss timeout
|
|
this->offBDSWS_nextBDDisTime = this->offBDSWS_nextBDInvTime + (this->off_BD_SWS.dismiss_bd_secs * 1000);
|
|
this->offBDSWS_nextSWSDisTime = this->offBDSWS_nextSWSInvTime + (this->off_BD_SWS.dismiss_sws_secs * 1000);
|
|
log_error( LOG_USERAI, "Enabled offparty BD/SWS invite\n" );
|
|
return;
|
|
}
|
|
if( (bEnable == 0) /*&& (this->off_BD_SWS.allEnabled == 1)*/ )
|
|
{
|
|
this->off_BD_SWS.allEnabled = 0;
|
|
log_error( LOG_USERAI, "Disabled offparty BD/SWS invite\n" );
|
|
}
|
|
}
|