#include "packetdefs.h" #include "../../clib/rawtypes.h" #include "../globals/settings.h" #include "../mobile/charactr.h" #include "../uobject.h" #include "client.h" #include "pktdef.h" namespace Pol { namespace Network { void SendWorldItem::Send( Client* client ) { if ( client->ClientType & CLIENTTYPE_7000 ) { if ( _p->offset == 1 ) buildF3(); if ( client->ClientType & CLIENTTYPE_7090 ) /*once known split class?*/ _p.Send( client, 26 ); else _p.Send( client, 24 ); } else { if ( _p_old->offset == 1 ) build1A(); _p_old.Send( client, _p_oldlen ); } } void SendWorldItem::updateFlags( u8 flags ) { if ( flags != _flags ) { _flags = flags; if ( _p_old->offset != 1 ) { _p_old->offset = _p_oldlen - 1; _p_old->Write( _flags ); } if ( _p->offset != 1 ) { _p->offset = 23; _p->Write( _flags ); } } } void SendWorldItem::build1A() { _p_old->offset = 1; // transmit item info _p_old->offset += 2; // If the 0x80000000 is left out, the item won't show up. _p_old->WriteFlipped( 0x80000000u | _serial ); // bit 0x80000000 enables piles _p_old->WriteFlipped( _graphic ); _p_old->WriteFlipped( _amount ); if ( _facing == 0 ) { _p_old->WriteFlipped( _pos.x() ); // bits 0x80 and 0x40 are Dye and Move (dunno which is which) _p_old->WriteFlipped( 0xC000u | _pos.y() ); // dyeable and moveable? } else { _p_old->WriteFlipped( 0x8000u | _pos.x() ); // bits 0x80 and 0x40 are Dye and Move (dunno which is which) _p_old->WriteFlipped( 0xC000u | _pos.y() ); // dyeable and moveable? _p_old->Write( _facing ); } _p_old->Write( _pos.z() ); _p_old->WriteFlipped( _color ); _p_old->Write( _flags ); _p_oldlen = _p_old->offset; _p_old->offset = 1; _p_old->WriteFlipped( _p_oldlen ); } void SendWorldItem::buildF3() { _p->offset = 1; _p->WriteFlipped( 0x1u ); _p->offset++; // datatype _p->WriteFlipped( _serial ); _p->WriteFlipped( _graphic ); _p->Write( 0u ); _p->WriteFlipped( _amount ); _p->WriteFlipped( _amount ); _p->WriteFlipped( _pos.x() ); _p->WriteFlipped( _pos.y() ); _p->Write( _pos.z() ); _p->Write( _facing ); _p->WriteFlipped( _color ); _p->Write( _flags ); } SendWorldItem::SendWorldItem( u32 serial, u16 graphic, u16 amount, Core::Pos3d pos, u8 facing, u16 color, u8 flags ) : PktSender(), _p_oldlen( 0 ), _serial( serial ), _graphic( graphic ), _amount( amount ), _pos( std::move( pos ) ), _facing( facing ), _color( color ), _flags( flags ), _p_old(), _p() { } SendWorldMulti::SendWorldMulti( u32 serial_ext, u16 graphic, Core::Pos3d pos, u16 color ) : PktSender(), _p_oldlen( 0 ), _serial_ext( serial_ext ), _graphic( graphic ), _pos( std::move( pos ) ), _color( color ), _p_old(), _p() { } void SendWorldMulti::build1A() { _p_old->offset = 1; _p_old->offset += 2; _p_old->Write( _serial_ext ); _p_old->WriteFlipped( _graphic | 0x4000u ); _p_old->WriteFlipped( _pos.x() ); _p_old->WriteFlipped( _pos.y() ); _p_old->Write( _pos.z() ); _p_oldlen = _p_old->offset; _p_old->offset = 1; _p_old->WriteFlipped( _p_oldlen ); } void SendWorldMulti::buildF3() { _p->offset = 1; _p->WriteFlipped( 0x1u ); _p->Write( 0x02u ); _p->Write( _serial_ext ); _p->WriteFlipped( _graphic ); _p->Write( 0u ); _p->WriteFlipped( 0x1u ); // amount _p->WriteFlipped( 0x1u ); // amount _p->WriteFlipped( _pos.x() ); _p->WriteFlipped( _pos.y() ); _p->Write( _pos.z() ); _p->Write( 0u ); // facing _p->WriteFlipped( _color ); _p->Write( 0u ); // flags } void SendWorldMulti::Send( Client* client ) { if ( client->ClientType & CLIENTTYPE_7000 ) { if ( _p->offset == 1 ) buildF3(); if ( client->ClientType & CLIENTTYPE_7090 ) /*once known split class?*/ _p.Send( client, 26 ); else _p.Send( client, 24 ); } else { if ( _p_old->offset == 1 ) build1A(); _p_old.Send( client, _p_oldlen ); } } AddItemContainerMsg::AddItemContainerMsg( u32 serial_ext, u16 graphic, u16 amount, Core::Pos2d pos, u8 slotindex, u32 containerserial_ext, u16 color ) : PktSender(), _serial_ext( serial_ext ), _graphic( graphic ), _amount( amount ), _pos( std::move( pos ) ), _slotindex( slotindex ), _containerserial_ext( containerserial_ext ), _color( color ), _p_old(), _p() { } void AddItemContainerMsg::buildLegacy() { _p_old->offset = 1; _p_old->Write( _serial_ext ); _p_old->WriteFlipped( _graphic ); _p_old->offset++; // unk7 layer? _p_old->WriteFlipped( _amount ); _p_old->WriteFlipped( _pos.x() ); _p_old->WriteFlipped( _pos.y() ); _p_old->Write( _containerserial_ext ); _p_old->WriteFlipped( _color ); } void AddItemContainerMsg::build() { _p->offset = 1; _p->Write( _serial_ext ); _p->WriteFlipped( _graphic ); _p->offset++; // unk7 layer? _p->WriteFlipped( _amount ); _p->WriteFlipped( _pos.x() ); _p->WriteFlipped( _pos.y() ); _p->Write( _slotindex ); _p->Write( _containerserial_ext ); _p->WriteFlipped( _color ); } void AddItemContainerMsg::Send( Client* client ) { if ( client->ClientType & CLIENTTYPE_6017 ) { if ( _p->offset == 1 ) build(); _p.Send( client, _p->getSize() ); } else { if ( _p_old->offset == 1 ) buildLegacy(); _p_old.Send( client, _p->getSize() - 1 ); } } MobileAnimationMsg::MobileAnimationMsg( u32 serial_ext ) : PktSender(), _serial_ext( serial_ext ), _anim( 0 ), _action( 0 ), _subaction( 0 ), _action_old( 0 ), _framecount_old( 0 ), _repeat_old( 0 ), _backward_old( 0 ), _repeat_flag_old( 0 ), _delay_old( 0 ), _oldanim_valid( false ), _newanim_valid( false ), _p_old(), _p() { } MobileAnimationMsg::MobileAnimationMsg( u32 serial_ext, u16 anim, u16 action, u8 subaction, u16 action_old, u16 framecount_old, u16 repeat_old, Core::DIRECTION_FLAG_OLD backward_old, Core::REPEAT_FLAG_OLD repeat_flag_old, u8 delay_old, bool oldanim_valid, bool newanim_valid ) : PktSender(), _serial_ext( serial_ext ), _anim( anim ), _action( action ), _subaction( subaction ), _action_old( action_old ), _framecount_old( framecount_old ), _repeat_old( repeat_old ), _backward_old( static_cast( backward_old ) ), _repeat_flag_old( static_cast( repeat_flag_old ) ), _delay_old( delay_old ), _oldanim_valid( oldanim_valid ), _newanim_valid( newanim_valid ), _p_old(), _p() { } void MobileAnimationMsg::update( u16 anim, u16 action, u8 subaction, u16 action_old, u16 framecount_old, u16 repeat_old, Core::DIRECTION_FLAG_OLD backward_old, Core::REPEAT_FLAG_OLD repeat_flag_old, u8 delay_old, bool oldanim_valid, bool newanim_valid ) { _anim = anim; _action = action; _subaction = subaction; _action_old = action_old; _framecount_old = framecount_old; _repeat_old = repeat_old; _backward_old = static_cast( backward_old ); _repeat_flag_old = static_cast( repeat_flag_old ); _delay_old = delay_old; _oldanim_valid = oldanim_valid; _newanim_valid = newanim_valid; if ( _oldanim_valid && _p_old->offset != 1 ) build6E(); if ( _newanim_valid && _p->offset != 1 ) build(); } void MobileAnimationMsg::build() { _p->offset = 1; _p->Write( _serial_ext ); _p->WriteFlipped( _anim ); _p->WriteFlipped( _action ); _p->Write( _subaction ); } void MobileAnimationMsg::build6E() { _p_old->offset = 1; _p_old->Write( _serial_ext ); _p_old->WriteFlipped( _action_old ); _p_old->WriteFlipped( _framecount_old ); _p_old->WriteFlipped( _repeat_old ); _p_old->Write( _backward_old ); _p_old->Write( _repeat_flag_old ); _p_old->Write( _delay_old ); } void MobileAnimationMsg::Send( Client* client ) { if ( client->ClientType & CLIENTTYPE_7090 ) { if ( !_newanim_valid ) return; if ( _p->offset == 1 ) build(); _p.Send( client, _p->getSize() ); } else { if ( !_oldanim_valid ) return; if ( _p_old->offset == 1 ) build6E(); _p_old.Send( client, _p_old->getSize() ); } } PlaySoundPkt::PlaySoundPkt( u8 type, u16 effect, Core::Pos3d center ) : PktSender(), _type( type ), _effect( effect ), _center( std::move( center ) ), _p() { } void PlaySoundPkt::Send( Client* client ) { if ( _p->offset == 1 ) build(); _p.Send( client, _p->getSize() ); } void PlaySoundPkt::build() { _p->offset = 1; _p->Write( _type ); _p->WriteFlipped( _effect ); _p->offset += 2; // volume _p->WriteFlipped( _center.x() ); _p->WriteFlipped( _center.y() ); _p->WriteFlipped( _center.z() ); } RemoveObjectPkt::RemoveObjectPkt( u32 serial_ext ) : _serial( serial_ext ), _p() {} void RemoveObjectPkt::update( u32 serial ) { _serial = serial; if ( _p->offset != 1 ) build(); } void RemoveObjectPkt::Send( Client* client ) { if ( _p->offset == 1 ) build(); _p.Send( client, _p->getSize() ); } void RemoveObjectPkt::build() { _p->offset = 1; _p->Write( _serial ); } SendDamagePkt::SendDamagePkt( u32 serial_ext, u16 damage ) : PktSender(), _serial( serial_ext ), _damage( damage ), _p_old(), _p() { } void SendDamagePkt::Send( Client* client ) { if ( client->ClientType & CLIENTTYPE_4070 ) { if ( _p->offset == 1 ) build(); _p.Send( client, _p->getSize() ); } else { if ( _p_old->offset == 1 ) buildold(); _p_old.Send( client ); } } void SendDamagePkt::build() { _p->offset = 1; _p->Write( _serial ); _p->WriteFlipped( _damage ); } void SendDamagePkt::buildold() { _p_old->offset = 1; _p_old->WriteFlipped( 11u ); _p_old->offset += 2; // sub _p_old->Write( 1u ); _p_old->Write( _serial ); if ( _damage > 0xFF ) _p_old->Write( 0xFFu ); else _p_old->Write( _damage ); } ObjRevisionPkt::ObjRevisionPkt( u32 serial_ext, u32 rev ) : PktSender(), _serial_ext( serial_ext ), _rev( rev ), _p_old(), _p() { } void ObjRevisionPkt::Send( Client* client ) { if ( client->UOExpansionFlag & AOS ) { if ( Core::settingsManager.ssopt.uo_feature_enable & Core::PKTOUT_A9::FLAG_AOS_FEATURES ) { if ( ( Core::settingsManager.ssopt.force_new_objcache_packets ) || ( client->ClientType & Network::CLIENTTYPE_5000 ) ) { if ( _p->offset == 1 ) build(); _p.Send( client, _p->getSize() ); } else { if ( _p_old->offset == 1 ) buildold(); _p_old.Send( client ); } } } } void ObjRevisionPkt::build() { _p->offset = 1; _p->Write( _serial_ext ); _p->WriteFlipped( _rev ); } void ObjRevisionPkt::buildold() { _p_old->offset = 1; _p_old->WriteFlipped( 0xDu ); _p_old->offset += 2; // sub _p_old->Write( _serial_ext ); _p_old->WriteFlipped( _rev ); } GraphicEffectPkt::GraphicEffectPkt() : PktSender(), _effect_type( 0 ), _src_serial_ext( 0 ), _dst_serial_ext( 0 ), _effect( 0 ), _src(), _dst(), _speed( 0 ), _loop( 0 ), _explode( 0 ), _unk26( 0 ), _p() { } void GraphicEffectPkt::movingEffect( const Core::UObject* src, const Core::UObject* dst, u16 effect, u8 speed, u8 loop, u8 explode ) { _effect_type = Core::PKTOUT_C0::EFFECT_MOVING; _src_serial_ext = src->serial_ext; _dst_serial_ext = dst->serial_ext; _effect = effect; _src = src->toplevel_pos().xyz() + Core::Vec3d( 0, 0, src->height ); _dst = dst->toplevel_pos().xyz() + Core::Vec3d( 0, 0, dst->height ); _speed = speed; _loop = loop; _explode = explode; } void GraphicEffectPkt::movingEffect( Core::Pos3d src, Core::Pos3d dst, u16 effect, u8 speed, u8 loop, u8 explode ) { _effect_type = Core::PKTOUT_C0::EFFECT_MOVING; _effect = effect; _src = std::move( src ); _dst = std::move( dst ); _speed = speed; _loop = loop; _explode = explode; } void GraphicEffectPkt::lightningBold( const Core::UObject* center ) { _effect_type = Core::PKTOUT_C0::EFFECT_LIGHTNING; _src_serial_ext = center->serial_ext; _src = center->toplevel_pos().xyz(); } void GraphicEffectPkt::followEffect( const Core::UObject* center, u16 effect, u8 speed, u8 loop ) { _effect_type = Core::PKTOUT_C0::EFFECT_FIXEDFROM; _src_serial_ext = center->serial_ext; _effect = effect; _src = center->toplevel_pos().xyz(); _speed = speed; _loop = loop; } void GraphicEffectPkt::stationaryEffect( Core::Pos3d src, u16 effect, u8 speed, u8 loop, u8 explode ) { _effect_type = Core::PKTOUT_C0::EFFECT_FIXEDXYZ; _effect = effect; _src = std::move( src ); _speed = speed; _loop = loop; _explode = explode; _unk26 = 1; // this is right for teleport, anyway } void GraphicEffectPkt::build() { _p->offset = 1; _p->Write( _effect_type ); _p->Write( _src_serial_ext ); _p->Write( _dst_serial_ext ); _p->WriteFlipped( _effect ); _p->WriteFlipped( _src.x() ); _p->WriteFlipped( _src.y() ); _p->Write( _src.z() ); _p->WriteFlipped( _dst.x() ); _p->WriteFlipped( _dst.y() ); _p->Write( _dst.z() ); _p->Write( _speed ); _p->Write( _loop ); _p->offset += 2; // unk24,unk25 _p->Write( _unk26 ); _p->Write( _explode ); } void GraphicEffectPkt::Send( Client* client ) { if ( _p->offset == 1 ) build(); _p.Send( client, _p->getSize() ); } GraphicEffectExPkt::GraphicEffectExPkt() : PktSender(), _effect_type( 0 ), _src_serial_ext( 0 ), _dst_serial_ext( 0 ), _effect( 0 ), _src(), _dst(), _speed( 0 ), _duration( 0 ), _direction( 0 ), _explode( 0 ), _hue( 0 ), _render( 0 ), _effect3d( 0 ), _effect3dexplode( 0 ), _effect3dsound( 0 ), _itemid( 0 ), _layer( 0 ), _p() { } void GraphicEffectExPkt::movingEffect( const Core::UObject* src, const Core::UObject* dst, u16 effect, u8 speed, u8 duration, u32 hue, u32 render, u8 direction, u8 explode, u16 effect3d, u16 effect3dexplode, u16 effect3dsound ) { _effect_type = Core::PKTOUT_C0::EFFECT_MOVING; _src_serial_ext = src->serial_ext; _dst_serial_ext = dst->serial_ext; _effect = effect; _src = src->toplevel_pos().xyz() + Core::Vec3d( 0, 0, src->height ); _dst = dst->toplevel_pos().xyz() + Core::Vec3d( 0, 0, dst->height ); _speed = speed; _duration = duration; _direction = direction; _explode = explode; _hue = hue; _render = render; _effect3d = effect3d; _effect3dexplode = effect3dexplode; _effect3dsound = effect3dsound; _layer = 0xFF; } void GraphicEffectExPkt::movingEffect( Core::Pos3d src, Core::Pos3d dst, u16 effect, u8 speed, u8 duration, u32 hue, u32 render, u8 direction, u8 explode, u16 effect3d, u16 effect3dexplode, u16 effect3dsound ) { _effect_type = Core::PKTOUT_C0::EFFECT_MOVING; _effect = effect; _src = std::move( src ); _dst = std::move( dst ); _speed = speed; _duration = duration; _direction = direction; _explode = explode; _hue = hue; _render = render; _effect3d = effect3d; _effect3dexplode = effect3dexplode; _effect3dsound = effect3dsound; _layer = 0xFF; } void GraphicEffectExPkt::followEffect( const Core::UObject* center, u16 effect, u8 speed, u8 duration, u32 hue, u32 render, u8 layer, u16 effect3d ) { _effect_type = Core::PKTOUT_C0::EFFECT_FIXEDFROM; _src_serial_ext = center->serial_ext; _dst_serial_ext = center->serial_ext; _effect = effect; _src = center->toplevel_pos().xyz(); _dst = center->toplevel_pos().xyz(); _speed = speed; _duration = duration; _direction = 1; _hue = hue; _render = render; _effect3d = effect3d; _effect3dexplode = 1; _itemid = center->serial_ext; _layer = layer; } void GraphicEffectExPkt::stationaryEffect( Core::Pos3d pos, u16 effect, u8 speed, u8 duration, u32 hue, u32 render, u16 effect3d ) { _effect_type = Core::PKTOUT_C0::EFFECT_FIXEDXYZ; _effect = effect; _src = pos; _dst = std::move( pos ); _speed = speed; _duration = duration; _direction = 1; _hue = hue; _render = render; _effect3d = effect3d; _effect3dexplode = 1; _layer = 0xFF; } void GraphicEffectExPkt::build() { // C0 part _p->offset = 1; _p->Write( _effect_type ); _p->Write( _src_serial_ext ); _p->Write( _dst_serial_ext ); _p->WriteFlipped( _effect ); _p->WriteFlipped( _src.x() ); _p->WriteFlipped( _src.y() ); _p->Write( _src.z() ); _p->WriteFlipped( _dst.x() ); _p->WriteFlipped( _dst.y() ); _p->Write( _dst.z() ); _p->Write( _speed ); _p->Write( _duration ); _p->offset += 2; // u16 unk _p->Write( _direction ); _p->Write( _explode ); _p->WriteFlipped( _hue ); _p->WriteFlipped( _render ); // C7 part _p->WriteFlipped( _effect3d ); // see particleffect subdir _p->WriteFlipped( _effect3dexplode ); // 0 if no explosion _p->WriteFlipped( _effect3dsound ); // for moving effects, 0 otherwise _p->Write( _itemid ); // if target is item (type 2), 0 otherwise _p->Write( _layer ); //(of the character, e.g left hand, right hand, 0-5,7, 0xff: moving // effect or target is no char) _p->offset += 2; // u16 unk_effect } void GraphicEffectExPkt::Send( Client* client ) { if ( _p->offset == 1 ) build(); _p.Send( client, _p->getSize() ); } HealthBarStatusUpdate::HealthBarStatusUpdate( u32 serial_ext, Color color, bool enable ) : PktSender(), _serial_ext( serial_ext ), _enable( enable ), _color( color ), _p() { } void HealthBarStatusUpdate::build() { _p->offset = 1; _p->WriteFlipped( _p->getSize() ); _p->Write( _serial_ext ); _p->WriteFlipped( 1u ); // unk _p->WriteFlipped( _color ); _p->Write( _enable ? 1u : 0u ); // flag } void HealthBarStatusUpdate::Send( Client* client ) { if ( client->ClientType & CLIENTTYPE_UOKR ) { if ( _p->offset == 1 ) build(); _p.Send( client ); } } MoveChrPkt::MoveChrPkt( const Mobile::Character* chr ) : PktSender(), _chr( chr ), _p() {} void MoveChrPkt::build() { _p->offset = 1; _p->Write( _chr->serial_ext ); _p->WriteFlipped( _chr->graphic ); _p->WriteFlipped( _chr->x() ); _p->WriteFlipped( _chr->y() ); _p->Write( _chr->z() ); _p->Write( ( _chr->dir & 0x80u ) | _chr->facing ); // NOTE, this only includes mask 0x07 of the last MOVE message _p->WriteFlipped( _chr->color ); } void MoveChrPkt::Send( Client* client ) { if ( _p->offset == 1 ) build(); _p->offset = 15; _p->Write( _chr->get_flag1( client ) ); _p->Write( _chr->hilite_color_idx( client->chr ) ); _p.Send( client ); } } // namespace Network } // namespace Pol