polserver/pol-core/pol/target.cpp
turleypol 6a2bd7c705 Merge remote-tracking branch 'origin/master' into vector_classes
* origin/master: (93 commits)
  Add support for dictionary creation (#277)
  Add do-while statement (#276)
  Add foreach loops (#275)
  New compiler: array initialization (#274)
  Disambiguator: figure out if label is a case statement dispatch selector, or should apply to a statement within the case dispatch group's block. (#273)
  New compiler: Add support for case statements (#272)
  Change "logical" to "bitwise". (#258)
  Fix divide-by-zero errors, and mask FormatError if it were thrown in a destructor. (#271)
  Add break and continue statements. (#270)
  New compiler: assignment to local and global variables. (#269)
  Add support for while loops (#268)
  Optimize if statements, and emit module functions in legacy order (#267)
  Optimizations: binary operators (#266)
  Add binary operators (#265)
  Add support for const declarations (#264)
  Handle default parameter values, pass-by-name, and return statements in functions. (#263)
  Add limited support for user functions (#262)
  New compiler: add return and exit statements (#261)
  Add support for if-then-else statements (#259)
  OG compiler: set module to Mod_Basic when a token is an identifier (#257)
  ...
2020-09-06 20:14:26 +02:00

440 lines
12 KiB
C++

/** @file
*
* @par History
* - 2009/07/23 MuadDib: updates for new Enum::Packet Out ID
* - 2009/09/03 MuadDib: Relocation of account related cpp/h
* Relocation of multi related cpp/h
*/
#include "target.h"
#include <stddef.h>
#include "../clib/clib_endian.h"
#include "../clib/logfacility.h"
#include "../clib/rawtypes.h"
#include "../plib/systemstate.h"
#include "fnsearch.h"
#include "globals/uvars.h"
#include "item/itemdesc.h"
#include "mobile/charactr.h"
#include "multi/multi.h"
#include "network/client.h"
#include "network/packethelper.h"
#include "network/packets.h"
#include "network/pktboth.h"
#include "polclass.h"
#include "realms/realm.h"
#include "regions/guardrgn.h"
#include "systems/suspiciousacts.h"
#include "ufunc.h"
#include "uobject.h"
namespace Pol
{
namespace Core
{
void handle_target_cursor( Network::Client* client, PKTBI_6C* msg )
{
Mobile::Character* targetter = client->chr;
u32 target_cursor_serial = cfBEu32( msg->target_cursor_serial );
// does target cursor even exist? (NOTE 1-based)
if ( target_cursor_serial == 0 ||
target_cursor_serial > gamestate.target_cursors._cursorid_count )
{
return;
}
TargetCursor* tcursor = gamestate.target_cursors._target_cursors[target_cursor_serial - 1];
if ( tcursor != targetter->tcursor2 )
{
SuspiciousActs::OutOfSequenceCursor( client );
targetter->tcursor2 = nullptr;
return;
}
targetter->tcursor2 = nullptr;
tcursor->handle_target_cursor( targetter, msg );
}
/*
Target Cursor messages come in different forms:
1) Item selected:
'create': 0
target_cursor_serial: serial of cursor
unk6: 0
selected_serial: serial of selected item
x: x-pos of selected item
y: y-pos of selected item
unk15: 0
z: z-pos of selected item
objtype: objtype of selected item
2) Character selected:
same as for (1)
3) Cursor Cancelled:
create is 0
target_cursor_serial: serial of cursor
unk6: 0
selected_serial: 0
x: 0xffff
y: 0xffff
unk15: 0
z: 0
objtype: 0
4) Static targetted:
create is 1
target_cursor_serial: serial of cursor
unk6: 0
selected_serial: 0
x: x-pos
y: y-pos
unk15: 0
z: z-pos
objtype: objtype of item
5) Backpack on a paperdoll selected
create is 0
target_cursor_serial: serial of cursor
cursor_type: 0
selected_serial: serial of backpack
x: 0xffff
y: 0xffff
unk15: 0
z: 0
objtype: objtype of backpack
*/
/*
struct {
void (*func)(Client *client, PKTBI_6C *msg);
} target_handlers[ MAX_CURSORS ];
*/
TargetCursor::TargetCursor( bool inform_on_cancel ) : inform_on_cancel_( inform_on_cancel )
{
if ( gamestate.target_cursors._cursorid_count > gamestate.target_cursors._target_cursors.size() )
{
throw std::runtime_error( "Too many targetting cursors!" );
}
cursorid_ = gamestate.target_cursors._cursorid_count;
gamestate.target_cursors._target_cursors[cursorid_ - 1] = this;
gamestate.target_cursors._cursorid_count++;
}
// FIXME we need something like is done for item menus, where we check
// to make sure that he client has any business using this menu - in this
// case, we need to make sure the client is supposed to have an active cursor.
bool TargetCursor::send_object_cursor( Network::Client* client, PKTBI_6C::CURSOR_TYPE crstype )
{
if ( !client->chr->target_cursor_busy() )
{
Network::PktHelper::PacketOut<Network::PktOut_6C> msg;
msg->Write<u8>( PKTBI_6C::UNK1_00 );
msg->WriteFlipped<u32>( cursorid_ );
msg->Write<u8>( crstype );
// rest 0
msg.Send( client, sizeof msg->buffer );
client->chr->tcursor2 = this;
return true;
}
else
{
return false;
}
}
void TargetCursor::cancel( Mobile::Character* chr )
{
chr->tcursor2 = nullptr;
if ( inform_on_cancel_ )
on_target_cursor( chr, nullptr );
}
void TargetCursor::handle_target_cursor( Mobile::Character* chr, PKTBI_6C* msg )
{
if ( msg->selected_serial != 0 ) // targetted something
{
if ( chr->dead() ) // but is dead
{
if ( chr->client != nullptr )
send_sysmessage( chr->client, "I am dead and cannot do that." );
cancel( chr );
return;
}
if ( ( chr->frozen() || chr->paralyzed() ) && !chr->can_freemove() )
{
if ( chr->client != nullptr )
{
if ( chr->frozen() )
private_say_above( chr, chr, "I am frozen and cannot do that." );
else if ( chr->paralyzed() )
private_say_above( chr, chr, "I am paralyzed and cannot do that." );
}
cancel( chr );
return;
}
u32 selected_serial = cfBEu32( msg->selected_serial );
UObject* obj = system_find_object( selected_serial );
if ( obj != nullptr && obj->script_isa( POLCLASS_MOBILE ) && !obj->script_isa( POLCLASS_NPC ) )
{
Mobile::Character* targeted = find_character( selected_serial );
// check for when char is not logged on
if ( targeted != nullptr )
{
if ( !chr->is_visible_to_me( targeted ) )
{
cancel( chr );
return;
}
if ( msg->cursor_type == 1 )
{
if ( ( JusticeRegion::RunNoCombatCheck( chr->client ) == true ) ||
( JusticeRegion::RunNoCombatCheck( targeted->client ) == true ) )
{
send_sysmessage( chr->client, "Combat is not allowed in this area." );
cancel( chr );
return;
}
}
}
}
}
if ( msg->x != 0xffff || msg->selected_serial != 0 )
on_target_cursor( chr, msg );
else
cancel( chr );
}
FullMsgTargetCursor::FullMsgTargetCursor( void ( *func )( Mobile::Character*, PKTBI_6C* ) )
: TargetCursor( false /* don't inform on cancel */ ), func( func )
{
}
void FullMsgTargetCursor::on_target_cursor( Mobile::Character* chr, PKTBI_6C* msg )
{
( *func )( chr, msg );
}
/******************************************************/
LosCheckedTargetCursor::LosCheckedTargetCursor( void ( *func )( Mobile::Character*, UObject* ),
bool inform_on_cancel )
: TargetCursor( inform_on_cancel ), func( func )
{
}
void LosCheckedTargetCursor::on_target_cursor( Mobile::Character* chr, PKTBI_6C* msgin )
{
if ( msgin == nullptr )
{
( *func )( chr, nullptr );
return;
}
u32 selected_serial = cfBEu32( msgin->selected_serial );
UObject* uobj = find_toplevel_object( selected_serial );
// FIXME inefficient, but neither works well by itself.
bool additlegal = false;
if ( uobj == nullptr )
uobj = find_legal_item( chr, selected_serial, &additlegal );
if ( uobj == nullptr )
uobj = system_find_multi( selected_serial );
if ( uobj == nullptr )
{
if ( chr->client != nullptr )
send_sysmessage( chr->client, "What you selected does not seem to exist." );
if ( inform_on_cancel_ )
( *func )( chr, nullptr );
return;
}
if ( !additlegal && !chr->realm()->has_los( *chr, *uobj->toplevel_owner() ) )
{
if ( chr->client != nullptr )
send_sysmessage( chr->client, "That is not within your line of sight." );
if ( inform_on_cancel_ )
( *func )( chr, nullptr );
return;
}
( *func )( chr, uobj );
}
/******************************************************/
/******************************************************/
NoLosCheckedTargetCursor::NoLosCheckedTargetCursor( void ( *func )( Mobile::Character*, UObject* ),
bool inform_on_cancel )
: TargetCursor( inform_on_cancel ), func( func )
{
}
void NoLosCheckedTargetCursor::on_target_cursor( Mobile::Character* chr, PKTBI_6C* msgin )
{
if ( msgin == nullptr )
{
( *func )( chr, nullptr );
return;
}
u32 selected_serial = cfBEu32( msgin->selected_serial );
UObject* uobj = find_toplevel_object( selected_serial );
// FIXME inefficient, but neither works well by itself.
bool additlegal = false;
if ( uobj == nullptr )
uobj = find_legal_item( chr, selected_serial, &additlegal );
if ( uobj == nullptr )
uobj = system_find_multi( selected_serial );
if ( uobj == nullptr )
{
if ( chr->client != nullptr )
send_sysmessage( chr->client, "What you selected does not seem to exist." );
if ( inform_on_cancel_ )
( *func )( chr, nullptr );
return;
}
( *func )( chr, uobj );
}
/******************************************************/
LosCheckedCoordCursor::LosCheckedCoordCursor( void ( *func )( Mobile::Character*, PKTBI_6C* ),
bool inform_on_cancel )
: TargetCursor( inform_on_cancel ), func_( func )
{
}
bool LosCheckedCoordCursor::send_coord_cursor( Network::Client* client )
{
if ( !client->chr->target_cursor_busy() )
{
Network::PktHelper::PacketOut<Network::PktOut_6C> msg;
msg->Write<u8>( PKTBI_6C::UNK1_01 );
msg->WriteFlipped<u32>( cursorid_ );
msg->Write<u8>( PKTBI_6C::CURSOR_TYPE_NEUTRAL );
// rest 0
msg.Send( client, sizeof msg->buffer );
client->chr->tcursor2 = this;
return true;
}
else
{
return false;
}
}
void LosCheckedCoordCursor::on_target_cursor( Mobile::Character* chr, PKTBI_6C* msg )
{
( *func_ )( chr, msg );
}
MultiPlacementCursor::MultiPlacementCursor( void ( *func )( Mobile::Character*, PKTBI_6C* ) )
: TargetCursor( true ), func_( func )
{
}
void MultiPlacementCursor::send_placemulti( Network::Client* client, unsigned int objtype,
int flags, s16 xoffset, s16 yoffset, u32 hue )
{
Network::PktHelper::PacketOut<Network::PktOut_99> msg;
msg->Write<u8>( 0x1u );
msg->WriteFlipped<u32>( cursorid_ );
msg->offset += 12; // 12x u8 unk
u16 multiid = Items::find_multidesc( objtype ).multiid;
multiid +=
static_cast<u16>( ( flags & Multi::CRMULTI_FACING_MASK ) >> Multi::CRMULTI_FACING_SHIFT );
msg->WriteFlipped<u16>( multiid );
msg->WriteFlipped<s16>( xoffset );
msg->WriteFlipped<s16>( yoffset );
msg->offset += 2; // u16 maybe_zoffset
if ( client->ClientType & Network::CLIENTTYPE_7090 )
msg->WriteFlipped<u32>( hue );
msg.Send( client );
client->chr->tcursor2 = this;
}
void MultiPlacementCursor::on_target_cursor( Mobile::Character* chr, PKTBI_6C* msg )
{
( *func_ )( chr, msg );
}
NoLosCharacterCursor::NoLosCharacterCursor( void ( *func )( Mobile::Character*,
Mobile::Character* ) )
: TargetCursor( false /* don't inform on cancel */ ), func( func )
{
}
void NoLosCharacterCursor::on_target_cursor( Mobile::Character* targetter, PKTBI_6C* msgin )
{
if ( msgin == nullptr )
return;
u32 selected_serial = cfBEu32( msgin->selected_serial );
Mobile::Character* chr = find_character( selected_serial );
if ( chr != nullptr )
( *func )( targetter, chr );
}
NoLosUObjectCursor::NoLosUObjectCursor( void ( *func )( Mobile::Character*, UObject* ),
bool inform_on_cancel )
: TargetCursor( inform_on_cancel ), func( func )
{
}
void NoLosUObjectCursor::on_target_cursor( Mobile::Character* targetter, PKTBI_6C* msgin )
{
if ( msgin == nullptr )
{
( *func )( targetter, nullptr );
return;
}
u32 selected_serial = cfBEu32( msgin->selected_serial );
UObject* obj = system_find_object( selected_serial );
if ( obj )
{
( *func )( targetter, obj );
}
else if ( inform_on_cancel_ )
{
( *func )( targetter, nullptr );
}
}
Cursors::Cursors()
: _target_cursors(), // NOTE: the id is 1-based (seems that the stealth client has problem with
// serial==0)
_cursorid_count(
1 ), // array and index needs to be initialized before registering the cursors
los_checked_script_cursor( Module::handle_script_cursor, true ),
nolos_checked_script_cursor( Module::handle_script_cursor, true ),
add_member_cursor( handle_add_member_cursor ),
remove_member_cursor( handle_remove_member_cursor ),
ident_cursor( handle_ident_cursor ),
script_cursor2( Module::handle_coord_cursor, true ),
multi_placement_cursor( Module::handle_coord_cursor ),
repdata_cursor( show_repdata ),
startlog_cursor( start_packetlog ),
stoplog_cursor( stop_packetlog )
{
}
} // namespace Core
} // namespace Pol