polserver/pol-core/pol/bowsalut.cpp
2018-12-30 21:35:54 +01:00

255 lines
8.6 KiB
C++

/** @file
*
* @par History
* - 2005/11/26 Shinigami: changed "strcmp" into "stricmp" to suppress Script Errors
* - 2009/07/27 MuadDib: Pakcet struct refactoring
*/
#include <string.h>
#include <string>
#include "../clib/cfgelem.h"
#include "../clib/cfgfile.h"
#include "../clib/clib.h"
#include "../clib/fileutil.h"
#include "../clib/logfacility.h"
#include "../clib/rawtypes.h"
#include "../clib/stlutil.h"
#include "action.h"
#include "globals/uvars.h"
#include "mobile/charactr.h"
#include "network/client.h"
#include "network/packetdefs.h"
#include "network/pktin.h"
#include "uworld.h"
namespace Pol
{
namespace Core
{
MobileTranslate::OldAnimDef::OldAnimDef()
: valid( false ),
action( 0 ),
framecount( 0 ),
repeatcount( 0 ),
backward( 0 ),
repeatflag( 0 ),
delay( 0 )
{
}
MobileTranslate::NewAnimDef::NewAnimDef() : valid( false ), anim( 0 ), action( 0 ), subaction( 0 )
{
}
MobileTranslate::MobileTranslate() : graphics(), supports_mount( false )
{
memset( &old_anim, 0, sizeof( old_anim ) );
memset( &new_anim, 0, sizeof( new_anim ) );
}
bool MobileTranslate::has_graphic( u16 graphic ) const
{
return std::find( graphics.begin(), graphics.end(), graphic ) != graphics.end();
}
size_t MobileTranslate::estimateSize() const
{
return sizeof( MobileTranslate ) + 3 * sizeof( u16* ) + graphics.capacity() * sizeof( u16 );
}
UACTION str_to_action( Clib::ConfigElem& elem, const std::string& str )
{
unsigned short tmp = static_cast<unsigned short>( strtoul( str.c_str(), nullptr, 0 ) );
if ( UACTION_IS_VALID( tmp ) )
{
return static_cast<UACTION>( tmp );
}
else
{
elem.throw_error( "Animation value of " + str + " is out of range" );
}
}
void load_anim_xlate_cfg( bool /*reload*/ )
{
memset( &Core::gamestate.mount_action_xlate, 0, sizeof( Core::gamestate.mount_action_xlate ) );
Core::gamestate.animation_translates.clear();
if ( Clib::FileExists( "config/animxlate.cfg" ) )
{
Clib::ConfigFile cf( "config/animxlate.cfg", "OnMount MobileType" );
Clib::ConfigElem elem;
while ( cf.read( elem ) )
{
if ( elem.type_is( "OnMount" ) )
{
std::string from_str, to_str;
while ( elem.remove_first_prop( &from_str, &to_str ) )
{
UACTION from = str_to_action( elem, from_str );
UACTION to = str_to_action( elem, to_str );
Core::gamestate.mount_action_xlate[from] = to;
}
}
else if ( elem.type_is( "MobileType" ) )
{
MobileTranslate mobiletype;
std::string key, value;
while ( elem.has_prop( "Graphic" ) )
{
mobiletype.graphics.push_back( elem.remove_ushort( "Graphic" ) );
}
std::sort( mobiletype.graphics.begin(), mobiletype.graphics.end() );
mobiletype.supports_mount = elem.remove_bool( "MountTranslation", false );
auto split_str = []( const std::string& source ) -> std::vector<std::string> {
ISTRINGSTREAM is( source );
std::string tmp;
std::vector<std::string> result;
while ( is >> tmp )
{
if ( tmp.empty() )
continue;
if ( tmp.at( 0 ) == '#' )
break;
result.push_back( tmp );
tmp.clear();
}
return result;
};
for ( int id = 0; id <= ACTION__HIGHEST; ++id )
{
std::string entry( "OldAnim" + std::to_string( id ) );
if ( elem.has_prop( entry.c_str() ) )
{
std::vector<std::string> values = split_str( elem.remove_string( entry.c_str() ) );
if ( !values.empty() )
{
mobiletype.old_anim[id].action =
static_cast<u16>( strtoul( values[0].c_str(), nullptr, 0 ) );
mobiletype.old_anim[id].valid = true;
mobiletype.old_anim[id].framecount = 5;
mobiletype.old_anim[id].repeatcount = 1;
mobiletype.old_anim[id].backward = 0;
mobiletype.old_anim[id].repeatflag = 0;
mobiletype.old_anim[id].delay = 1;
}
if ( values.size() > 1 )
mobiletype.old_anim[id].framecount =
static_cast<u16>( strtoul( values[1].c_str(), nullptr, 0 ) );
if ( values.size() > 2 )
mobiletype.old_anim[id].repeatcount =
static_cast<u16>( strtoul( values[2].c_str(), nullptr, 0 ) );
if ( values.size() > 3 )
mobiletype.old_anim[id].backward =
static_cast<u8>( strtoul( values[3].c_str(), nullptr, 0 ) );
if ( values.size() > 4 )
mobiletype.old_anim[id].repeatflag =
static_cast<u8>( strtoul( values[4].c_str(), nullptr, 0 ) );
if ( values.size() > 5 )
mobiletype.old_anim[id].delay =
static_cast<u8>( strtoul( values[5].c_str(), nullptr, 0 ) );
}
entry = "NewAnim" + std::to_string( id );
if ( elem.has_prop( entry.c_str() ) )
{
std::vector<std::string> values = split_str( elem.remove_string( entry.c_str() ) );
if ( !values.empty() )
{
mobiletype.new_anim[id].anim =
static_cast<u16>( strtoul( values[0].c_str(), nullptr, 0 ) );
mobiletype.new_anim[id].valid = true;
mobiletype.new_anim[id].action = 0;
mobiletype.new_anim[id].subaction = 0;
}
if ( values.size() > 1 )
mobiletype.new_anim[id].action =
static_cast<u16>( strtoul( values[1].c_str(), nullptr, 0 ) );
if ( values.size() > 2 )
mobiletype.new_anim[id].subaction =
static_cast<u8>( strtoul( values[2].c_str(), nullptr, 0 ) );
}
}
Core::gamestate.animation_translates[elem.rest()] = mobiletype;
}
}
}
}
void send_action_to_inrange( const Mobile::Character* obj, UACTION action,
unsigned short framecount /*=0x05*/,
unsigned short repeatcount /*=0x01*/,
DIRECTION_FLAG_OLD backward /*=PKTOUT_6E::FORWARD*/,
REPEAT_FLAG_OLD repeatflag /*=PKTOUT_6E::NOREPEAT*/,
unsigned char delay /*=0x01*/ )
{
bool build = false;
Network::MobileAnimationMsg msg( obj->serial_ext );
WorldIterator<OnlinePlayerFilter>::InVisualRange( obj, [&]( Mobile::Character* zonechr ) {
if ( !build ) // only build if client in range
{
MobileTranslate::OldAnimDef oldanim;
oldanim.valid = true;
oldanim.action = static_cast<u16>( action );
oldanim.framecount = framecount;
oldanim.repeatcount = repeatcount;
oldanim.backward = static_cast<u8>( backward );
oldanim.repeatflag = static_cast<u8>( repeatflag );
oldanim.delay = delay;
MobileTranslate::NewAnimDef newanim;
bool supports_mount = true;
build = true;
MobileTranslate const* translate = nullptr;
for ( const auto& translates : Core::gamestate.animation_translates )
{
if ( translates.second.has_graphic( obj->graphic ) )
{
translate = &translates.second;
supports_mount = translate->supports_mount;
break;
}
}
if ( obj->on_mount() && supports_mount )
{
if ( action < ACTION_RIDINGHORSE1 || action > ACTION_RIDINGHORSE7 )
{
UACTION new_action = Core::gamestate.mount_action_xlate[action];
if ( new_action == 0 )
return;
action = new_action;
oldanim.action = static_cast<u16>( new_action );
}
}
if ( translate != nullptr )
{
oldanim = translate->old_anim[action];
newanim = translate->new_anim[action];
}
else
{
ERROR_PRINT << "Warning: undefined animXlate.cfg entry for graphic 0x"
<< fmt::hexu( obj->graphic ) << "\n";
}
msg.update( newanim.anim, newanim.action, newanim.subaction, oldanim.action,
oldanim.framecount, oldanim.repeatcount,
static_cast<DIRECTION_FLAG_OLD>( oldanim.backward ),
static_cast<REPEAT_FLAG_OLD>( oldanim.repeatflag ), oldanim.delay, oldanim.valid,
newanim.valid );
}
msg.Send( zonechr->client );
} );
}
void handle_action( Network::Client* client, PKTIN_12* cmd )
{
if ( stricmp( (const char*)cmd->data, "bow" ) == 0 )
send_action_to_inrange( client->chr, ACTION_BOW );
else if ( stricmp( (const char*)cmd->data, "salute" ) == 0 )
send_action_to_inrange( client->chr, ACTION_SALUTE );
}
} // namespace Core
} // namespace Pol