2017-03-07 00:09:37 -05:00
using FFXIVClassic.Common ;
2019-05-04 20:53:08 -04:00
using System ;
using System.Collections.Generic ;
using MoonSharp.Interpreter ;
2017-03-07 00:09:37 -05:00
using FFXIVClassic_Map_Server.dataobjects ;
using FFXIVClassic_Map_Server.dataobjects.chara ;
using FFXIVClassic_Map_Server.lua ;
2019-05-04 20:53:08 -04:00
using FFXIVClassic_Map_Server.packets.WorldPackets.Send.Group ;
2017-03-07 00:09:37 -05:00
using FFXIVClassic_Map_Server.utils ;
2016-12-04 10:51:27 -05:00
using FFXIVClassic_Map_Server.actors.group ;
2019-05-04 20:53:08 -04:00
using FFXIVClassic_Map_Server.actors.chara.player ;
using FFXIVClassic_Map_Server.actors.director ;
2017-09-05 12:37:23 -04:00
using FFXIVClassic_Map_Server.actors.chara.npc ;
2017-06-12 20:13:26 +01:00
using FFXIVClassic_Map_Server.actors.chara.ai ;
using FFXIVClassic_Map_Server.actors.chara.ai.controllers ;
2017-08-28 04:45:20 +01:00
using FFXIVClassic_Map_Server.actors.chara.ai.utils ;
using FFXIVClassic_Map_Server.actors.chara.ai.state ;
2018-02-15 13:20:46 -06:00
using FFXIVClassic_Map_Server.actors.chara ;
2019-05-04 20:53:08 -04:00
using FFXIVClassic_Map_Server.packets.send ;
using FFXIVClassic_Map_Server.packets.send.actor ;
using FFXIVClassic_Map_Server.packets.send.events ;
using FFXIVClassic_Map_Server.packets.send.actor.inventory ;
using FFXIVClassic_Map_Server.packets.send.player ;
using FFXIVClassic_Map_Server.packets.send.actor.battle ;
using FFXIVClassic_Map_Server.packets.receive.events ;
2019-06-02 16:57:46 -04:00
using static FFXIVClassic_Map_Server . LuaUtils ;
2016-08-22 10:43:04 -04:00
2017-03-07 00:09:37 -05:00
namespace FFXIVClassic_Map_Server.Actors
{
class Player : Character
{
public const int TIMER_TOTORAK = 0 ;
public const int TIMER_DZEMAEL = 1 ;
public const int TIMER_BOWL_OF_EMBERS_HARD = 2 ;
public const int TIMER_BOWL_OF_EMBERS = 3 ;
public const int TIMER_THORNMARCH = 4 ;
public const int TIMER_AURUMVALE = 5 ;
public const int TIMER_CUTTERSCRY = 6 ;
public const int TIMER_BATTLE_ALEPORT = 7 ;
public const int TIMER_BATTLE_HYRSTMILL = 8 ;
public const int TIMER_BATTLE_GOLDENBAZAAR = 9 ;
public const int TIMER_HOWLING_EYE_HARD = 10 ;
public const int TIMER_HOWLING_EYE = 11 ;
public const int TIMER_CASTRUM_TOWER = 12 ;
public const int TIMER_BOWL_OF_EMBERS_EXTREME = 13 ;
public const int TIMER_RIVENROAD = 14 ;
public const int TIMER_RIVENROAD_HARD = 15 ;
public const int TIMER_BEHEST = 16 ;
public const int TIMER_COMPANYBEHEST = 17 ;
public const int TIMER_RETURN = 18 ;
public const int TIMER_SKIRMISH = 19 ;
2017-04-09 14:01:15 -04:00
public const int NPCLS_GONE = 0 ;
public const int NPCLS_INACTIVE = 1 ;
public const int NPCLS_ACTIVE = 2 ;
public const int NPCLS_ALERT = 3 ;
2019-06-02 16:57:46 -04:00
public const int SLOT_MAINHAND = 0 ;
public const int SLOT_OFFHAND = 1 ;
public const int SLOT_THROWINGWEAPON = 4 ;
public const int SLOT_PACK = 5 ;
public const int SLOT_POUCH = 6 ;
public const int SLOT_HEAD = 8 ;
public const int SLOT_UNDERSHIRT = 9 ;
public const int SLOT_BODY = 10 ;
public const int SLOT_UNDERGARMENT = 11 ;
public const int SLOT_LEGS = 12 ;
public const int SLOT_HANDS = 13 ;
public const int SLOT_BOOTS = 14 ;
public const int SLOT_WAIST = 15 ;
public const int SLOT_NECK = 16 ;
public const int SLOT_EARS = 17 ;
public const int SLOT_WRISTS = 19 ;
public const int SLOT_RIGHTFINGER = 21 ;
public const int SLOT_LEFTFINGER = 22 ;
2017-03-07 00:09:37 -05:00
public static int [ ] MAXEXP = { 570 , 700 , 880 , 1100 , 1500 , 1800 , 2300 , 3200 , 4300 , 5000 , //Level <= 10
5900 , 6800 , 7700 , 8700 , 9700 , 11000 , 12000 , 13000 , 15000 , 16000 , //Level <= 20
20000 , 22000 , 23000 , 25000 , 27000 , 29000 , 31000 , 33000 , 35000 , 38000 , //Level <= 30
45000 , 47000 , 50000 , 53000 , 56000 , 59000 , 62000 , 65000 , 68000 , 71000 , //Level <= 40
74000 , 78000 , 81000 , 85000 , 89000 , 92000 , 96000 , 100000 , 100000 , 110000 } ; //Level <= 50
//Event Related
public uint currentEventOwner = 0 ;
public string currentEventName = "" ;
public Coroutine currentEventRunning ;
//Player Info
public uint destinationZone ;
public ushort destinationSpawnType ;
public uint [ ] timers = new uint [ 20 ] ;
public uint currentTitle ;
public uint playTime ;
public uint lastPlayTimeUpdate ;
public bool isGM = false ;
public bool isZoneChanging = true ;
2017-10-01 12:23:54 -04:00
//Trading
private Player otherTrader = null ;
2019-06-02 16:57:46 -04:00
private ReferencedItemPackage myOfferings ;
2017-10-08 12:26:22 -04:00
private bool isTradeAccepted = false ;
2017-03-07 00:09:37 -05:00
//GC Related
public byte gcCurrent ;
public byte gcRankLimsa ;
public byte gcRankGridania ;
public byte gcRankUldah ;
//Mount Related
public bool hasChocobo ;
public bool hasGoobbue ;
public byte chocoboAppearance ;
public string chocoboName ;
public byte mountState = 0 ;
public uint achievementPoints ;
//Property Array Request Stuff
private int lastPosition = 0 ;
private int lastStep = 0 ;
//Quest Actors (MUST MATCH playerWork.questScenario/questGuildleve)
public Quest [ ] questScenario = new Quest [ 16 ] ;
2017-06-24 12:07:27 -04:00
public uint [ ] questGuildleve = new uint [ 8 ] ;
2017-03-07 00:09:37 -05:00
2017-05-01 22:30:43 -04:00
//Aetheryte
public uint homepoint = 0 ;
public byte homepointInn = 0 ;
2017-11-11 10:56:15 -05:00
//Nameplate Stuff
public uint currentLSPlate = 0 ;
public byte repairType = 0 ;
2017-09-09 10:54:40 -04:00
//Retainer
RetainerMeetingRelationGroup retainerMeetingGroup = null ;
2017-09-05 12:37:23 -04:00
public Retainer currentSpawnedRetainer = null ;
public bool sentRetainerSpawn = false ;
2017-03-07 00:09:37 -05:00
private List < Director > ownedDirectors = new List < Director > ( ) ;
private Director loginInitDirector = null ;
public PlayerWork playerWork = new PlayerWork ( ) ;
public Session playerSession ;
public Player ( Session cp , uint actorID ) : base ( actorID )
{
playerSession = cp ;
actorName = String . Format ( "_pc{0:00000000}" , actorID ) ;
className = "Player" ;
2017-06-06 17:33:02 -04:00
moveSpeeds [ 0 ] = SetActorSpeedPacket . DEFAULT_STOP ;
moveSpeeds [ 1 ] = SetActorSpeedPacket . DEFAULT_WALK ;
moveSpeeds [ 2 ] = SetActorSpeedPacket . DEFAULT_RUN ;
moveSpeeds [ 3 ] = SetActorSpeedPacket . DEFAULT_ACTIVE ;
2019-06-02 16:57:46 -04:00
itemPackages [ ItemPackage . NORMAL ] = new ItemPackage ( this , ItemPackage . MAXSIZE_NORMAL , ItemPackage . NORMAL ) ;
itemPackages [ ItemPackage . KEYITEMS ] = new ItemPackage ( this , ItemPackage . MAXSIZE_KEYITEMS , ItemPackage . KEYITEMS ) ;
itemPackages [ ItemPackage . CURRENCY_CRYSTALS ] = new ItemPackage ( this , ItemPackage . MAXSIZE_CURRANCY , ItemPackage . CURRENCY_CRYSTALS ) ;
itemPackages [ ItemPackage . MELDREQUEST ] = new ItemPackage ( this , ItemPackage . MAXSIZE_MELDREQUEST , ItemPackage . MELDREQUEST ) ;
itemPackages [ ItemPackage . BAZAAR ] = new ItemPackage ( this , ItemPackage . MAXSIZE_BAZAAR , ItemPackage . BAZAAR ) ;
itemPackages [ ItemPackage . LOOT ] = new ItemPackage ( this , ItemPackage . MAXSIZE_LOOT , ItemPackage . LOOT ) ;
equipment = new ReferencedItemPackage ( this , ItemPackage . MAXSIZE_EQUIPMENT , ItemPackage . EQUIPMENT ) ;
2017-03-07 00:09:37 -05:00
//Set the Skill level caps of all FFXIV (classes)skills to 50
for ( int i = 0 ; i < charaWork . battleSave . skillLevelCap . Length ; i + + )
{
if ( i ! = CLASSID_PUG & &
i ! = CLASSID_MRD & &
i ! = CLASSID_GLA & &
i ! = CLASSID_MRD & &
i ! = CLASSID_ARC & &
i ! = CLASSID_LNC & &
i ! = CLASSID_THM & &
i ! = CLASSID_CNJ & &
i ! = CLASSID_CRP & &
i ! = CLASSID_BSM & &
i ! = CLASSID_ARM & &
i ! = CLASSID_GSM & &
i ! = CLASSID_LTW & &
i ! = CLASSID_WVR & &
i ! = CLASSID_ALC & &
i ! = CLASSID_CUL & &
i ! = CLASSID_MIN & &
i ! = CLASSID_BTN & &
i ! = CLASSID_FSH )
charaWork . battleSave . skillLevelCap [ i ] = 0xFF ;
else
charaWork . battleSave . skillLevelCap [ i ] = 50 ;
}
charaWork . property [ 0 ] = 1 ;
charaWork . property [ 1 ] = 1 ;
charaWork . property [ 2 ] = 1 ;
charaWork . property [ 4 ] = 1 ;
charaWork . command [ 0 ] = 0xA0F00000 | 21001 ;
charaWork . command [ 1 ] = 0xA0F00000 | 21001 ;
charaWork . command [ 2 ] = 0xA0F00000 | 21002 ;
charaWork . command [ 3 ] = 0xA0F00000 | 12004 ;
charaWork . command [ 4 ] = 0xA0F00000 | 21005 ;
charaWork . command [ 5 ] = 0xA0F00000 | 21006 ;
charaWork . command [ 6 ] = 0xA0F00000 | 21007 ;
charaWork . command [ 7 ] = 0xA0F00000 | 12009 ;
charaWork . command [ 8 ] = 0xA0F00000 | 12010 ;
charaWork . command [ 9 ] = 0xA0F00000 | 12005 ;
charaWork . command [ 10 ] = 0xA0F00000 | 12007 ;
charaWork . command [ 11 ] = 0xA0F00000 | 12011 ;
charaWork . command [ 12 ] = 0xA0F00000 | 22012 ;
charaWork . command [ 13 ] = 0xA0F00000 | 22013 ;
charaWork . command [ 14 ] = 0xA0F00000 | 29497 ;
2017-07-07 21:53:44 -05:00
charaWork . command [ 15 ] = 0xA0F00000 | 22015 ;
2017-03-07 00:09:37 -05:00
charaWork . commandAcquired [ 27150 - 26000 ] = true ;
playerWork . questScenarioComplete [ 110001 - 110001 ] = true ;
playerWork . questGuildleveComplete [ 120050 - 120001 ] = true ;
for ( int i = 0 ; i < charaWork . additionalCommandAcquired . Length ; i + + )
charaWork . additionalCommandAcquired [ i ] = true ;
for ( int i = 0 ; i < charaWork . commandCategory . Length ; i + + )
charaWork . commandCategory [ i ] = 1 ;
charaWork . battleTemp . generalParameter [ 3 ] = 1 ;
charaWork . eventSave . bazaarTax = 5 ;
charaWork . battleSave . potencial = 6.6f ;
2017-08-26 16:59:15 -04:00
charaWork . battleSave . negotiationFlag [ 0 ] = true ;
2017-03-07 00:09:37 -05:00
charaWork . commandCategory [ 0 ] = 1 ;
charaWork . commandCategory [ 1 ] = 1 ;
charaWork . parameterSave . commandSlot_compatibility [ 0 ] = true ;
charaWork . parameterSave . commandSlot_compatibility [ 1 ] = true ;
charaWork . commandBorder = 0x20 ;
2017-10-10 13:32:47 -05:00
charaWork . parameterTemp . tp = 0 ;
2017-03-07 00:09:37 -05:00
Database . LoadPlayerCharacter ( this ) ;
lastPlayTimeUpdate = Utils . UnixTimeStampUTC ( ) ;
2017-10-01 12:23:54 -04:00
2017-06-12 20:13:26 +01:00
this . aiContainer = new AIContainer ( this , new PlayerController ( this ) , null , new TargetFind ( this ) ) ;
2017-07-11 01:54:15 +01:00
allegiance = CharacterTargetingAllegiance . Player ;
2018-02-15 13:20:46 -06:00
CalculateBaseStats ( ) ;
2017-03-07 00:09:37 -05:00
}
2017-06-27 13:52:47 -04:00
public List < SubPacket > Create0x132Packets ( )
2017-03-07 00:09:37 -05:00
{
List < SubPacket > packets = new List < SubPacket > ( ) ;
2017-06-27 13:52:47 -04:00
packets . Add ( _0x132Packet . BuildPacket ( actorId , 0xB , "commandForced" ) ) ;
packets . Add ( _0x132Packet . BuildPacket ( actorId , 0xA , "commandDefault" ) ) ;
packets . Add ( _0x132Packet . BuildPacket ( actorId , 0x6 , "commandWeak" ) ) ;
packets . Add ( _0x132Packet . BuildPacket ( actorId , 0x4 , "commandContent" ) ) ;
packets . Add ( _0x132Packet . BuildPacket ( actorId , 0x6 , "commandJudgeMode" ) ) ;
packets . Add ( _0x132Packet . BuildPacket ( actorId , 0x100 , "commandRequest" ) ) ;
packets . Add ( _0x132Packet . BuildPacket ( actorId , 0x100 , "widgetCreate" ) ) ;
packets . Add ( _0x132Packet . BuildPacket ( actorId , 0x100 , "macroRequest" ) ) ;
2017-03-07 00:09:37 -05:00
return packets ;
}
/ *
* PLAYER ARGS :
* Unknown - Bool
* Unknown - Bool
* Is Init Director - Bool
* Unknown - Bool
* Unknown - Number
* Unknown - Bool
* Timer Array - 20 Number
* /
2017-06-27 16:55:14 -04:00
public override SubPacket CreateScriptBindPacket ( Player requestPlayer )
2017-03-07 00:09:37 -05:00
{
List < LuaParam > lParams ;
2017-06-27 16:55:14 -04:00
if ( IsMyPlayer ( requestPlayer . actorId ) )
2017-03-07 00:09:37 -05:00
{
if ( loginInitDirector ! = null )
lParams = LuaUtils . CreateLuaParamList ( "/Chara/Player/Player_work" , false , false , true , loginInitDirector , true , 0 , false , timers , true ) ;
else
lParams = LuaUtils . CreateLuaParamList ( "/Chara/Player/Player_work" , true , false , false , true , 0 , false , timers , true ) ;
}
else
lParams = LuaUtils . CreateLuaParamList ( "/Chara/Player/Player_work" , false , false , false , false , false , true ) ;
2017-06-27 13:52:47 -04:00
ActorInstantiatePacket . BuildPacket ( actorId , actorName , className , lParams ) . DebugPrintSubPacket ( ) ;
2017-03-07 00:09:37 -05:00
2019-01-29 00:02:09 -05:00
2017-06-27 13:52:47 -04:00
return ActorInstantiatePacket . BuildPacket ( actorId , actorName , className , lParams ) ;
2017-03-07 00:09:37 -05:00
}
2017-06-27 21:08:30 -04:00
public override List < SubPacket > GetSpawnPackets ( Player requestPlayer , ushort spawnType )
2017-03-07 00:09:37 -05:00
{
List < SubPacket > subpackets = new List < SubPacket > ( ) ;
2017-06-27 16:55:14 -04:00
subpackets . Add ( CreateAddActorPacket ( 8 ) ) ;
if ( IsMyPlayer ( requestPlayer . actorId ) )
2017-06-27 13:52:47 -04:00
subpackets . AddRange ( Create0x132Packets ( ) ) ;
subpackets . Add ( CreateSpeedPacket ( ) ) ;
2017-06-27 21:30:32 -04:00
subpackets . Add ( CreateSpawnPositonPacket ( this , spawnType ) ) ;
2017-06-27 13:52:47 -04:00
subpackets . Add ( CreateAppearancePacket ( ) ) ;
subpackets . Add ( CreateNamePacket ( ) ) ;
subpackets . Add ( _0xFPacket . BuildPacket ( actorId ) ) ;
subpackets . Add ( CreateStatePacket ( ) ) ;
2018-10-20 13:15:58 -04:00
subpackets . Add ( CreateSubStatePacket ( ) ) ;
2017-06-27 13:52:47 -04:00
subpackets . Add ( CreateInitStatusPacket ( ) ) ;
subpackets . Add ( CreateSetActorIconPacket ( ) ) ;
subpackets . Add ( CreateIsZoneingPacket ( ) ) ;
2017-06-27 16:55:14 -04:00
subpackets . AddRange ( CreatePlayerRelatedPackets ( requestPlayer . actorId ) ) ;
subpackets . Add ( CreateScriptBindPacket ( requestPlayer ) ) ;
2017-06-27 21:08:30 -04:00
return subpackets ;
2017-03-07 00:09:37 -05:00
}
2017-06-27 16:55:14 -04:00
public List < SubPacket > CreatePlayerRelatedPackets ( uint requestingPlayerActorId )
2017-03-07 00:09:37 -05:00
{
List < SubPacket > subpackets = new List < SubPacket > ( ) ;
if ( gcCurrent ! = 0 )
2017-06-27 13:52:47 -04:00
subpackets . Add ( SetGrandCompanyPacket . BuildPacket ( actorId , gcCurrent , gcRankLimsa , gcRankGridania , gcRankUldah ) ) ;
2017-03-07 00:09:37 -05:00
if ( currentTitle ! = 0 )
2017-06-27 13:52:47 -04:00
subpackets . Add ( SetPlayerTitlePacket . BuildPacket ( actorId , currentTitle ) ) ;
2017-03-07 00:09:37 -05:00
if ( currentJob ! = 0 )
2017-06-27 13:52:47 -04:00
subpackets . Add ( SetCurrentJobPacket . BuildPacket ( actorId , currentJob ) ) ;
2017-03-07 00:09:37 -05:00
2017-06-27 16:55:14 -04:00
if ( IsMyPlayer ( requestingPlayerActorId ) )
2017-03-07 00:09:37 -05:00
{
2017-06-27 13:52:47 -04:00
subpackets . Add ( SetSpecialEventWorkPacket . BuildPacket ( actorId ) ) ;
2017-03-07 00:09:37 -05:00
if ( hasChocobo & & chocoboName ! = null & & ! chocoboName . Equals ( "" ) )
{
2017-06-27 13:52:47 -04:00
subpackets . Add ( SetChocoboNamePacket . BuildPacket ( actorId , chocoboName ) ) ;
subpackets . Add ( SetHasChocoboPacket . BuildPacket ( actorId , hasChocobo ) ) ;
2017-03-07 00:09:37 -05:00
}
if ( hasGoobbue )
2017-06-27 13:52:47 -04:00
subpackets . Add ( SetHasGoobbuePacket . BuildPacket ( actorId , hasGoobbue ) ) ;
2017-03-07 00:09:37 -05:00
2017-06-27 13:52:47 -04:00
subpackets . Add ( SetAchievementPointsPacket . BuildPacket ( actorId , achievementPoints ) ) ;
2016-08-19 16:32:14 -05:00
2017-03-07 00:09:37 -05:00
subpackets . Add ( Database . GetLatestAchievements ( this ) ) ;
subpackets . Add ( Database . GetAchievementsPacket ( this ) ) ;
}
2017-07-06 21:59:12 -04:00
if ( mountState = = 1 )
subpackets . Add ( SetCurrentMountChocoboPacket . BuildPacket ( actorId , chocoboAppearance ) ) ;
else if ( mountState = = 2 )
subpackets . Add ( SetCurrentMountGoobbuePacket . BuildPacket ( actorId , 1 ) ) ;
2017-03-07 00:09:37 -05:00
return subpackets ;
}
2017-06-27 21:08:30 -04:00
public override List < SubPacket > GetInitPackets ( )
2017-03-07 00:09:37 -05:00
{
2017-06-27 13:52:47 -04:00
ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil ( "/_init" , this ) ;
2017-03-07 00:09:37 -05:00
propPacketUtil . AddProperty ( "charaWork.eventSave.bazaarTax" ) ;
propPacketUtil . AddProperty ( "charaWork.battleSave.potencial" ) ;
//Properties
for ( int i = 0 ; i < charaWork . property . Length ; i + + )
{
if ( charaWork . property [ i ] ! = 0 )
propPacketUtil . AddProperty ( String . Format ( "charaWork.property[{0}]" , i ) ) ;
}
//Parameters
propPacketUtil . AddProperty ( "charaWork.parameterSave.hp[0]" ) ;
propPacketUtil . AddProperty ( "charaWork.parameterSave.hpMax[0]" ) ;
propPacketUtil . AddProperty ( "charaWork.parameterSave.mp" ) ;
propPacketUtil . AddProperty ( "charaWork.parameterSave.mpMax" ) ;
propPacketUtil . AddProperty ( "charaWork.parameterTemp.tp" ) ;
propPacketUtil . AddProperty ( "charaWork.parameterSave.state_mainSkill[0]" ) ;
propPacketUtil . AddProperty ( "charaWork.parameterSave.state_mainSkillLevel" ) ;
//Status Times
for ( int i = 0 ; i < charaWork . statusShownTime . Length ; i + + )
{
2018-02-15 13:20:46 -06:00
if ( charaWork . statusShownTime [ i ] ! = 0 )
2017-03-07 00:09:37 -05:00
propPacketUtil . AddProperty ( String . Format ( "charaWork.statusShownTime[{0}]" , i ) ) ;
}
//General Parameters
for ( int i = 3 ; i < charaWork . battleTemp . generalParameter . Length ; i + + )
{
if ( charaWork . battleTemp . generalParameter [ i ] ! = 0 )
propPacketUtil . AddProperty ( String . Format ( "charaWork.battleTemp.generalParameter[{0}]" , i ) ) ;
}
propPacketUtil . AddProperty ( "charaWork.battleTemp.castGauge_speed[0]" ) ;
propPacketUtil . AddProperty ( "charaWork.battleTemp.castGauge_speed[1]" ) ;
2017-09-30 07:28:08 -05:00
2017-03-07 00:09:37 -05:00
//Battle Save Skillpoint
2018-10-08 15:11:43 -04:00
propPacketUtil . AddProperty ( String . Format ( "charaWork.battleSave.skillPoint[{0}]" , charaWork . parameterSave . state_mainSkill [ 0 ] - 1 ) ) ;
2017-09-30 07:28:08 -05:00
2017-03-07 00:09:37 -05:00
//Commands
propPacketUtil . AddProperty ( "charaWork.commandBorder" ) ;
2019-05-04 20:13:29 -04:00
2017-08-26 16:59:15 -04:00
propPacketUtil . AddProperty ( "charaWork.battleSave.negotiationFlag[0]" ) ;
2019-05-04 20:13:29 -04:00
2017-03-07 00:09:37 -05:00
for ( int i = 0 ; i < charaWork . command . Length ; i + + )
{
if ( charaWork . command [ i ] ! = 0 )
2017-08-22 14:50:53 -05:00
{
2017-03-07 00:09:37 -05:00
propPacketUtil . AddProperty ( String . Format ( "charaWork.command[{0}]" , i ) ) ;
2017-08-22 14:50:53 -05:00
//Recast Timers
if ( i > = charaWork . commandBorder )
{
propPacketUtil . AddProperty ( String . Format ( "charaWork.parameterTemp.maxCommandRecastTime[{0}]" , i - charaWork . commandBorder ) ) ;
propPacketUtil . AddProperty ( String . Format ( "charaWork.parameterSave.commandSlot_recastTime[{0}]" , i - charaWork . commandBorder ) ) ;
}
}
2017-03-07 00:09:37 -05:00
}
for ( int i = 0 ; i < charaWork . commandCategory . Length ; i + + )
{
charaWork . commandCategory [ i ] = 1 ;
if ( charaWork . commandCategory [ i ] ! = 0 )
propPacketUtil . AddProperty ( String . Format ( "charaWork.commandCategory[{0}]" , i ) ) ;
}
for ( int i = 0 ; i < charaWork . commandAcquired . Length ; i + + )
{
if ( charaWork . commandAcquired [ i ] ! = false )
propPacketUtil . AddProperty ( String . Format ( "charaWork.commandAcquired[{0}]" , i ) ) ;
}
for ( int i = 0 ; i < charaWork . additionalCommandAcquired . Length ; i + + )
{
if ( charaWork . additionalCommandAcquired [ i ] ! = false )
propPacketUtil . AddProperty ( String . Format ( "charaWork.additionalCommandAcquired[{0}]" , i ) ) ;
}
for ( int i = 0 ; i < charaWork . parameterSave . commandSlot_compatibility . Length ; i + + )
{
charaWork . parameterSave . commandSlot_compatibility [ i ] = true ;
if ( charaWork . parameterSave . commandSlot_compatibility [ i ] )
propPacketUtil . AddProperty ( String . Format ( "charaWork.parameterSave.commandSlot_compatibility[{0}]" , i ) ) ;
}
2017-09-30 07:28:08 -05:00
for ( int i = 0 ; i < charaWork . parameterSave . commandSlot_recastTime . Length ; i + + )
{
if ( charaWork . parameterSave . commandSlot_recastTime [ i ] ! = 0 )
propPacketUtil . AddProperty ( String . Format ( "charaWork.parameterSave.commandSlot_recastTime[{0}]" , i ) ) ;
}
2017-03-07 00:09:37 -05:00
//System
propPacketUtil . AddProperty ( "charaWork.parameterTemp.forceControl_float_forClientSelf[0]" ) ;
propPacketUtil . AddProperty ( "charaWork.parameterTemp.forceControl_float_forClientSelf[1]" ) ;
propPacketUtil . AddProperty ( "charaWork.parameterTemp.forceControl_int16_forClientSelf[0]" ) ;
propPacketUtil . AddProperty ( "charaWork.parameterTemp.forceControl_int16_forClientSelf[1]" ) ;
charaWork . parameterTemp . otherClassAbilityCount [ 0 ] = 4 ;
charaWork . parameterTemp . otherClassAbilityCount [ 1 ] = 5 ;
charaWork . parameterTemp . giftCount [ 1 ] = 5 ;
propPacketUtil . AddProperty ( "charaWork.parameterTemp.otherClassAbilityCount[0]" ) ;
propPacketUtil . AddProperty ( "charaWork.parameterTemp.otherClassAbilityCount[1]" ) ;
propPacketUtil . AddProperty ( "charaWork.parameterTemp.giftCount[1]" ) ;
propPacketUtil . AddProperty ( "charaWork.depictionJudge" ) ;
//Scenario
for ( int i = 0 ; i < playerWork . questScenario . Length ; i + + )
{
if ( playerWork . questScenario [ i ] ! = 0 )
propPacketUtil . AddProperty ( String . Format ( "playerWork.questScenario[{0}]" , i ) ) ;
}
//Guildleve - Local
for ( int i = 0 ; i < playerWork . questGuildleve . Length ; i + + )
{
if ( playerWork . questGuildleve [ i ] ! = 0 )
propPacketUtil . AddProperty ( String . Format ( "playerWork.questGuildleve[{0}]" , i ) ) ;
}
//Guildleve - Regional
for ( int i = 0 ; i < work . guildleveId . Length ; i + + )
{
if ( work . guildleveId [ i ] ! = 0 )
propPacketUtil . AddProperty ( String . Format ( "work.guildleveId[{0}]" , i ) ) ;
if ( work . guildleveDone [ i ] ! = false )
propPacketUtil . AddProperty ( String . Format ( "work.guildleveDone[{0}]" , i ) ) ;
if ( work . guildleveChecked [ i ] ! = false )
propPacketUtil . AddProperty ( String . Format ( "work.guildleveChecked[{0}]" , i ) ) ;
}
2017-11-11 10:56:15 -05:00
//Bazaar
2017-12-10 13:38:53 -05:00
CheckBazaarFlags ( true ) ;
2017-11-11 10:56:15 -05:00
if ( charaWork . eventSave . repairType ! = 0 )
propPacketUtil . AddProperty ( "charaWork.eventSave.repairType" ) ;
if ( charaWork . eventTemp . bazaarRetail )
propPacketUtil . AddProperty ( "charaWork.eventTemp.bazaarRetail" ) ;
if ( charaWork . eventTemp . bazaarRepair )
propPacketUtil . AddProperty ( "charaWork.eventTemp.bazaarRepair" ) ;
if ( charaWork . eventTemp . bazaarMateria )
propPacketUtil . AddProperty ( "charaWork.eventTemp.bazaarMateria" ) ;
//NPC Linkshell
2017-03-07 00:09:37 -05:00
for ( int i = 0 ; i < playerWork . npcLinkshellChatCalling . Length ; i + + )
{
if ( playerWork . npcLinkshellChatCalling [ i ] ! = false )
propPacketUtil . AddProperty ( String . Format ( "playerWork.npcLinkshellChatCalling[{0}]" , i ) ) ;
if ( playerWork . npcLinkshellChatExtra [ i ] ! = false )
propPacketUtil . AddProperty ( String . Format ( "playerWork.npcLinkshellChatExtra[{0}]" , i ) ) ;
}
propPacketUtil . AddProperty ( "playerWork.restBonusExpRate" ) ;
//Profile
propPacketUtil . AddProperty ( "playerWork.tribe" ) ;
propPacketUtil . AddProperty ( "playerWork.guardian" ) ;
propPacketUtil . AddProperty ( "playerWork.birthdayMonth" ) ;
propPacketUtil . AddProperty ( "playerWork.birthdayDay" ) ;
propPacketUtil . AddProperty ( "playerWork.initialTown" ) ;
2017-06-27 21:08:30 -04:00
return propPacketUtil . Done ( ) ;
2017-03-07 00:09:37 -05:00
}
public void SendSeamlessZoneInPackets ( )
{
QueuePacket ( SetMusicPacket . BuildPacket ( actorId , zone . bgmDay , SetMusicPacket . EFFECT_FADEIN ) ) ;
QueuePacket ( SetWeatherPacket . BuildPacket ( actorId , SetWeatherPacket . WEATHER_CLEAR , 1 ) ) ;
}
public void SendZoneInPackets ( WorldManager world , ushort spawnType )
{
2017-06-27 13:52:47 -04:00
QueuePacket ( SetActorIsZoningPacket . BuildPacket ( actorId , false ) ) ;
2017-10-01 12:31:45 -04:00
QueuePacket ( SetDalamudPacket . BuildPacket ( actorId , 0 ) ) ;
2017-03-07 00:09:37 -05:00
QueuePacket ( SetMusicPacket . BuildPacket ( actorId , zone . bgmDay , 0x01 ) ) ;
QueuePacket ( SetWeatherPacket . BuildPacket ( actorId , SetWeatherPacket . WEATHER_CLEAR , 1 ) ) ;
QueuePacket ( SetMapPacket . BuildPacket ( actorId , zone . regionId , zone . actorId ) ) ;
2017-06-27 21:40:49 -04:00
QueuePackets ( GetSpawnPackets ( this , spawnType ) ) ;
2017-03-07 00:09:37 -05:00
//GetSpawnPackets(actorId, spawnType).DebugPrintPacket();
#region Inventory & Equipment
2017-12-10 15:13:33 -05:00
QueuePacket ( InventoryBeginChangePacket . BuildPacket ( actorId , true ) ) ;
2019-06-02 16:57:46 -04:00
itemPackages [ ItemPackage . NORMAL ] . SendFullPackage ( this ) ;
itemPackages [ ItemPackage . CURRENCY_CRYSTALS ] . SendFullPackage ( this ) ;
itemPackages [ ItemPackage . KEYITEMS ] . SendFullPackage ( this ) ;
itemPackages [ ItemPackage . BAZAAR ] . SendFullPackage ( this ) ;
itemPackages [ ItemPackage . MELDREQUEST ] . SendFullPackage ( this ) ;
itemPackages [ ItemPackage . LOOT ] . SendFullPackage ( this ) ;
equipment . SendUpdate ( this ) ;
2017-06-27 13:52:47 -04:00
playerSession . QueuePacket ( InventoryEndChangePacket . BuildPacket ( actorId ) ) ;
2017-03-07 00:09:37 -05:00
#endregion
2017-06-27 13:52:47 -04:00
playerSession . QueuePacket ( GetInitPackets ( ) ) ;
2017-03-07 00:09:37 -05:00
2017-06-27 21:08:30 -04:00
List < SubPacket > areaMasterSpawn = zone . GetSpawnPackets ( ) ;
List < SubPacket > debugSpawn = world . GetDebugActor ( ) . GetSpawnPackets ( ) ;
List < SubPacket > worldMasterSpawn = world . GetActor ( ) . GetSpawnPackets ( ) ;
2017-03-07 00:09:37 -05:00
playerSession . QueuePacket ( areaMasterSpawn ) ;
2017-07-07 21:53:44 -05:00
playerSession . QueuePacket ( debugSpawn ) ;
2017-03-07 00:09:37 -05:00
playerSession . QueuePacket ( worldMasterSpawn ) ;
2017-06-19 22:21:21 -04:00
//Inn Packets (Dream, Cutscenes, Armoire)
2017-08-26 13:53:23 -04:00
2017-03-07 00:09:37 -05:00
if ( zone . isInn )
{
SetCutsceneBookPacket cutsceneBookPacket = new SetCutsceneBookPacket ( ) ;
for ( int i = 0 ; i < 2048 ; i + + )
cutsceneBookPacket . cutsceneFlags [ i ] = true ;
SubPacket packet = cutsceneBookPacket . BuildPacket ( actorId , "<Path Companion>" , 11 , 1 , 1 ) ;
packet . DebugPrintSubPacket ( ) ;
QueuePacket ( packet ) ;
2017-06-19 22:21:21 -04:00
QueuePacket ( SetPlayerItemStoragePacket . BuildPacket ( actorId ) ) ;
2017-03-07 00:09:37 -05:00
}
if ( zone . GetWeatherDirector ( ) ! = null )
{
2017-06-27 21:08:30 -04:00
playerSession . QueuePacket ( zone . GetWeatherDirector ( ) . GetSpawnPackets ( ) ) ;
2017-03-07 00:09:37 -05:00
}
foreach ( Director director in ownedDirectors )
{
2017-06-27 21:40:49 -04:00
QueuePackets ( director . GetSpawnPackets ( ) ) ;
QueuePackets ( director . GetInitPackets ( ) ) ;
2017-04-29 20:30:54 -04:00
}
if ( currentContentGroup ! = null )
currentContentGroup . SendGroupPackets ( playerSession ) ;
2017-12-08 00:58:39 -06:00
if ( currentParty ! = null )
currentParty . SendGroupPackets ( playerSession ) ;
2017-03-07 00:09:37 -05:00
}
private void SendRemoveInventoryPackets ( List < ushort > slots )
{
int currentIndex = 0 ;
while ( true )
{
if ( slots . Count - currentIndex > = 64 )
QueuePacket ( InventoryRemoveX64Packet . BuildPacket ( actorId , slots , ref currentIndex ) ) ;
else if ( slots . Count - currentIndex > = 32 )
QueuePacket ( InventoryRemoveX32Packet . BuildPacket ( actorId , slots , ref currentIndex ) ) ;
else if ( slots . Count - currentIndex > = 16 )
QueuePacket ( InventoryRemoveX16Packet . BuildPacket ( actorId , slots , ref currentIndex ) ) ;
else if ( slots . Count - currentIndex > = 8 )
QueuePacket ( InventoryRemoveX08Packet . BuildPacket ( actorId , slots , ref currentIndex ) ) ;
else if ( slots . Count - currentIndex = = 1 )
QueuePacket ( InventoryRemoveX01Packet . BuildPacket ( actorId , slots [ currentIndex ] ) ) ;
else
break ;
}
}
public bool IsMyPlayer ( uint otherActorId )
{
return actorId = = otherActorId ;
}
public void QueuePacket ( SubPacket packet )
2017-08-26 13:53:23 -04:00
2017-03-07 00:09:37 -05:00
{
2017-06-27 13:52:47 -04:00
playerSession . QueuePacket ( packet ) ;
2017-03-07 00:09:37 -05:00
}
public void QueuePackets ( List < SubPacket > packets )
{
2017-06-27 21:40:49 -04:00
playerSession . QueuePacket ( packets ) ;
2017-03-07 00:09:37 -05:00
}
public void SendPacket ( string path )
{
try
{
2017-08-26 10:23:13 -04:00
BasePacket packet = new BasePacket ( path ) ;
2017-03-07 00:09:37 -05:00
2017-08-26 10:23:13 -04:00
packet . ReplaceActorID ( actorId ) ;
2017-08-02 23:06:11 +01:00
var packets = packet . GetSubpackets ( ) ;
QueuePackets ( packets ) ;
2017-03-07 00:09:37 -05:00
}
catch ( Exception e )
{
this . SendMessage ( SendMessagePacket . MESSAGE_TYPE_SYSTEM_ERROR , "[SendPacket]" , "Unable to send packet." ) ;
2018-02-15 13:20:46 -06:00
this . SendMessage ( SendMessagePacket . MESSAGE_TYPE_SYSTEM_ERROR , "[SendPacket]" , e . Message ) ;
2017-03-07 00:09:37 -05:00
}
}
2017-12-10 22:53:37 -05:00
public void BroadcastPackets ( List < SubPacket > packets , bool sendToSelf )
{
foreach ( SubPacket packet in packets )
{
if ( sendToSelf )
{
SubPacket clonedPacket = new SubPacket ( packet , actorId ) ;
QueuePacket ( clonedPacket ) ;
}
foreach ( Actor a in playerSession . actorInstanceList )
{
if ( a is Player )
{
Player p = ( Player ) a ;
if ( p . Equals ( this ) )
continue ;
SubPacket clonedPacket = new SubPacket ( packet , a . actorId ) ;
p . QueuePacket ( clonedPacket ) ;
}
}
}
}
2017-03-07 00:09:37 -05:00
public void BroadcastPacket ( SubPacket packet , bool sendToSelf )
{
2017-07-06 21:59:12 -04:00
if ( sendToSelf )
{
SubPacket clonedPacket = new SubPacket ( packet , actorId ) ;
QueuePacket ( clonedPacket ) ;
}
2017-03-07 00:09:37 -05:00
foreach ( Actor a in playerSession . actorInstanceList )
{
if ( a is Player )
{
Player p = ( Player ) a ;
2017-07-06 21:59:12 -04:00
if ( p . Equals ( this ) )
2017-03-07 00:09:37 -05:00
continue ;
SubPacket clonedPacket = new SubPacket ( packet , a . actorId ) ;
p . QueuePacket ( clonedPacket ) ;
}
}
}
2017-03-08 09:12:14 -05:00
public void ChangeAnimation ( uint animId )
{
2017-04-15 16:33:56 -04:00
Actor a = zone . FindActorInArea ( currentTarget ) ;
2017-03-08 09:12:14 -05:00
if ( a is Npc )
( ( Npc ) a ) . animationId = animId ;
}
2017-03-07 00:09:37 -05:00
public void SetDCFlag ( bool flag )
{
if ( flag )
{
2017-06-27 13:52:47 -04:00
BroadcastPacket ( SetActorIconPacket . BuildPacket ( actorId , SetActorIconPacket . DISCONNECTING ) , true ) ;
2017-03-07 00:09:37 -05:00
}
else
{
if ( isGM )
2017-06-27 13:52:47 -04:00
BroadcastPacket ( SetActorIconPacket . BuildPacket ( actorId , SetActorIconPacket . ISGM ) , true ) ;
2017-03-07 00:09:37 -05:00
else
2017-06-27 13:52:47 -04:00
BroadcastPacket ( SetActorIconPacket . BuildPacket ( actorId , 0 ) , true ) ;
2017-03-07 00:09:37 -05:00
}
}
public void CleanupAndSave ( )
{
playerSession . LockUpdates ( true ) ;
//Remove actor from zone and main server list
zone . RemoveActorFromZone ( this ) ;
//Set Destination to 0
this . destinationZone = 0 ;
this . destinationSpawnType = 0 ;
//Clean up parties
RemoveFromCurrentPartyAndCleanup ( ) ;
//Save Player
Database . SavePlayerPlayTime ( this ) ;
Database . SavePlayerPosition ( this ) ;
2017-07-16 17:35:10 +01:00
Database . SavePlayerStatusEffects ( this ) ;
2017-03-07 00:09:37 -05:00
}
public void CleanupAndSave ( uint destinationZone , ushort spawnType , float destinationX , float destinationY , float destinationZ , float destinationRot )
{
playerSession . LockUpdates ( true ) ;
//Remove actor from zone and main server list
zone . RemoveActorFromZone ( this ) ;
//Clean up parties
RemoveFromCurrentPartyAndCleanup ( ) ;
//Set destination
this . destinationZone = destinationZone ;
this . destinationSpawnType = spawnType ;
this . positionX = destinationX ;
this . positionY = destinationY ;
this . positionZ = destinationZ ;
this . rotation = destinationRot ;
//Save Player
Database . SavePlayerPlayTime ( this ) ;
2017-08-26 13:53:23 -04:00
Database . SavePlayerPosition ( this ) ;
2017-07-16 17:35:10 +01:00
this . statusEffects . RemoveStatusEffectsByFlags ( ( uint ) StatusEffectFlags . LoseOnZoning , true ) ;
Database . SavePlayerStatusEffects ( this ) ;
2017-03-07 00:09:37 -05:00
}
public Area GetZone ( )
{
return zone ;
}
public void SendMessage ( uint logType , string sender , string message )
{
2017-06-27 13:52:47 -04:00
QueuePacket ( SendMessagePacket . BuildPacket ( actorId , logType , sender , message ) ) ;
2017-03-07 00:09:37 -05:00
}
public void Logout ( )
{
2017-07-16 17:35:10 +01:00
// todo: really this should be in CleanupAndSave but we might want logout/disconnect handled separately for some effects
2017-03-07 00:09:37 -05:00
QueuePacket ( LogoutPacket . BuildPacket ( actorId ) ) ;
2017-07-16 17:35:10 +01:00
statusEffects . RemoveStatusEffectsByFlags ( ( uint ) StatusEffectFlags . LoseOnLogout ) ;
2017-03-07 00:09:37 -05:00
CleanupAndSave ( ) ;
}
public void QuitGame ( )
{
QueuePacket ( QuitPacket . BuildPacket ( actorId ) ) ;
2017-07-16 17:35:10 +01:00
statusEffects . RemoveStatusEffectsByFlags ( ( uint ) StatusEffectFlags . LoseOnLogout ) ;
2017-03-07 00:09:37 -05:00
CleanupAndSave ( ) ;
}
public uint GetPlayTime ( bool doUpdate )
{
if ( doUpdate )
{
uint curTime = Utils . UnixTimeStampUTC ( ) ;
playTime + = curTime - lastPlayTimeUpdate ;
lastPlayTimeUpdate = curTime ;
}
return playTime ;
}
public void SavePlayTime ( )
{
Database . SavePlayerPlayTime ( this ) ;
}
public void ChangeMusic ( ushort musicId )
{
QueuePacket ( SetMusicPacket . BuildPacket ( actorId , musicId , 1 ) ) ;
}
2017-07-06 21:59:12 -04:00
public void SendMountAppearance ( )
2017-03-07 00:09:37 -05:00
{
2017-07-06 21:59:12 -04:00
if ( mountState = = 1 )
BroadcastPacket ( SetCurrentMountChocoboPacket . BuildPacket ( actorId , chocoboAppearance ) , true ) ;
else if ( mountState = = 2 )
BroadcastPacket ( SetCurrentMountGoobbuePacket . BuildPacket ( actorId , 1 ) , true ) ;
2017-03-07 00:09:37 -05:00
}
public void SetMountState ( byte mountState )
{
this . mountState = mountState ;
2017-07-06 21:59:12 -04:00
SendMountAppearance ( ) ;
2017-03-07 00:09:37 -05:00
}
public byte GetMountState ( )
{
return mountState ;
}
2017-06-15 00:19:18 -04:00
public void DoEmote ( uint targettedActor , uint animId , uint descId )
2017-03-07 00:09:37 -05:00
{
2017-06-27 13:52:47 -04:00
BroadcastPacket ( ActorDoEmotePacket . BuildPacket ( actorId , targettedActor , animId , descId ) , true ) ;
2017-03-07 00:09:37 -05:00
}
public void SendGameMessage ( Actor sourceActor , Actor textIdOwner , ushort textId , byte log , params object [ ] msgParams )
{
if ( msgParams = = null | | msgParams . Length = = 0 )
{
2017-06-27 13:52:47 -04:00
QueuePacket ( GameMessagePacket . BuildPacket ( Server . GetWorldManager ( ) . GetActor ( ) . actorId , sourceActor . actorId , textIdOwner . actorId , textId , log ) ) ;
2017-03-07 00:09:37 -05:00
}
else
2017-06-27 13:52:47 -04:00
QueuePacket ( GameMessagePacket . BuildPacket ( Server . GetWorldManager ( ) . GetActor ( ) . actorId , sourceActor . actorId , textIdOwner . actorId , textId , log , LuaUtils . CreateLuaParamList ( msgParams ) ) ) ;
2017-03-07 00:09:37 -05:00
}
public void SendGameMessage ( Actor textIdOwner , ushort textId , byte log , params object [ ] msgParams )
{
if ( msgParams = = null | | msgParams . Length = = 0 )
2017-06-27 13:52:47 -04:00
QueuePacket ( GameMessagePacket . BuildPacket ( Server . GetWorldManager ( ) . GetActor ( ) . actorId , textIdOwner . actorId , textId , log ) ) ;
2017-03-07 00:09:37 -05:00
else
2017-06-27 13:52:47 -04:00
QueuePacket ( GameMessagePacket . BuildPacket ( Server . GetWorldManager ( ) . GetActor ( ) . actorId , textIdOwner . actorId , textId , log , LuaUtils . CreateLuaParamList ( msgParams ) ) ) ;
2017-03-07 00:09:37 -05:00
}
2017-06-25 14:25:54 -04:00
public void SendGameMessageCustomSender ( Actor textIdOwner , ushort textId , byte log , string customSender , params object [ ] msgParams )
2017-03-07 00:09:37 -05:00
{
if ( msgParams = = null | | msgParams . Length = = 0 )
2017-06-27 13:52:47 -04:00
QueuePacket ( GameMessagePacket . BuildPacket ( Server . GetWorldManager ( ) . GetActor ( ) . actorId , textIdOwner . actorId , textId , customSender , log ) ) ;
2017-03-07 00:09:37 -05:00
else
2017-06-27 13:52:47 -04:00
QueuePacket ( GameMessagePacket . BuildPacket ( Server . GetWorldManager ( ) . GetActor ( ) . actorId , textIdOwner . actorId , textId , customSender , log , LuaUtils . CreateLuaParamList ( msgParams ) ) ) ;
2017-03-07 00:09:37 -05:00
}
2017-06-25 14:25:54 -04:00
public void SendGameMessageDisplayIDSender ( Actor textIdOwner , ushort textId , byte log , uint displayId , params object [ ] msgParams )
2017-03-07 00:09:37 -05:00
{
if ( msgParams = = null | | msgParams . Length = = 0 )
2017-06-27 13:52:47 -04:00
QueuePacket ( GameMessagePacket . BuildPacket ( Server . GetWorldManager ( ) . GetActor ( ) . actorId , textIdOwner . actorId , textId , displayId , log ) ) ;
2017-03-07 00:09:37 -05:00
else
2017-06-27 13:52:47 -04:00
QueuePacket ( GameMessagePacket . BuildPacket ( Server . GetWorldManager ( ) . GetActor ( ) . actorId , textIdOwner . actorId , textId , displayId , log , LuaUtils . CreateLuaParamList ( msgParams ) ) ) ;
2017-03-07 00:09:37 -05:00
}
public void BroadcastWorldMessage ( ushort worldMasterId , params object [ ] msgParams )
{
//SubPacket worldMasterMessage =
//zone.BroadcastPacketAroundActor(this, worldMasterMessage);
}
public void GraphicChange ( uint slot , uint graphicId )
{
appearanceIds [ slot ] = graphicId ;
}
public void GraphicChange ( uint slot , uint weapId , uint equipId , uint variantId , uint colorId )
{
uint mixedVariantId ;
if ( weapId = = 0 )
mixedVariantId = ( ( variantId & 0x1F ) < < 5 ) | colorId ;
else
mixedVariantId = variantId ;
uint graphicId =
( weapId & 0x3FF ) < < 20 |
( equipId & 0x3FF ) < < 10 |
( mixedVariantId & 0x3FF ) ;
appearanceIds [ slot ] = graphicId ;
}
public void SendAppearance ( )
{
2017-06-27 13:52:47 -04:00
BroadcastPacket ( CreateAppearancePacket ( ) , true ) ;
2017-03-07 00:09:37 -05:00
}
public void SendCharaExpInfo ( )
{
if ( lastStep = = 0 )
{
int maxLength ;
if ( ( sizeof ( short ) * charaWork . battleSave . skillLevel . Length ) - lastPosition < 0x5E )
maxLength = ( sizeof ( short ) * charaWork . battleSave . skillLevel . Length ) - lastPosition ;
else
maxLength = 0x5E ;
byte [ ] skillLevelBuffer = new byte [ maxLength ] ;
Buffer . BlockCopy ( charaWork . battleSave . skillLevel , 0 , skillLevelBuffer , 0 , skillLevelBuffer . Length ) ;
SetActorPropetyPacket charaInfo1 = new SetActorPropetyPacket ( "charaWork/exp" ) ;
charaInfo1 . SetIsArrayMode ( true ) ;
if ( maxLength = = 0x5E )
{
charaInfo1 . AddBuffer ( Utils . MurmurHash2 ( "charaWork.battleSave.skillLevel" , 0 ) , skillLevelBuffer , 0 , skillLevelBuffer . Length , 0x0 ) ;
lastPosition + = maxLength ;
}
else
{
charaInfo1 . AddBuffer ( Utils . MurmurHash2 ( "charaWork.battleSave.skillLevel" , 0 ) , skillLevelBuffer , 0 , skillLevelBuffer . Length , 0x3 ) ;
lastPosition = 0 ;
lastStep + + ;
}
charaInfo1 . AddTarget ( ) ;
2017-06-27 13:52:47 -04:00
QueuePacket ( charaInfo1 . BuildPacket ( actorId ) ) ;
2017-03-07 00:09:37 -05:00
}
else if ( lastStep = = 1 )
{
int maxLength ;
if ( ( sizeof ( short ) * charaWork . battleSave . skillLevelCap . Length ) - lastPosition < 0x5E )
maxLength = ( sizeof ( short ) * charaWork . battleSave . skillLevelCap . Length ) - lastPosition ;
else
maxLength = 0x5E ;
byte [ ] skillCapBuffer = new byte [ maxLength ] ;
Buffer . BlockCopy ( charaWork . battleSave . skillLevelCap , lastPosition , skillCapBuffer , 0 , skillCapBuffer . Length ) ;
SetActorPropetyPacket charaInfo1 = new SetActorPropetyPacket ( "charaWork/exp" ) ;
if ( maxLength = = 0x5E )
{
charaInfo1 . SetIsArrayMode ( true ) ;
charaInfo1 . AddBuffer ( Utils . MurmurHash2 ( "charaWork.battleSave.skillLevelCap" , 0 ) , skillCapBuffer , 0 , skillCapBuffer . Length , 0x1 ) ;
lastPosition + = maxLength ;
}
else
{
charaInfo1 . SetIsArrayMode ( false ) ;
charaInfo1 . AddBuffer ( Utils . MurmurHash2 ( "charaWork.battleSave.skillLevelCap" , 0 ) , skillCapBuffer , 0 , skillCapBuffer . Length , 0x3 ) ;
lastStep = 0 ;
lastPosition = 0 ;
}
charaInfo1 . AddTarget ( ) ;
2017-06-27 13:52:47 -04:00
QueuePacket ( charaInfo1 . BuildPacket ( actorId ) ) ;
2017-03-07 00:09:37 -05:00
}
}
2017-04-04 01:10:26 -04:00
public int GetHighestLevel ( )
{
int max = 0 ;
foreach ( short level in charaWork . battleSave . skillLevel )
{
if ( level > max )
max = level ;
}
return max ;
}
2019-06-04 00:11:36 -04:00
public InventoryItem [ ] GetGearset ( ushort classId )
2017-03-07 00:09:37 -05:00
{
return Database . GetEquipment ( this , classId ) ;
}
public void PrepareClassChange ( byte classId )
{
//If new class, init abilties and level
2018-04-07 15:34:11 -04:00
if ( charaWork . battleSave . skillLevel [ classId - 1 ] < = 0 )
UpdateClassLevel ( classId , 1 ) ;
2017-01-29 11:07:28 -05:00
2017-03-07 00:09:37 -05:00
SendCharaExpInfo ( ) ;
}
public void DoClassChange ( byte classId )
2016-08-05 18:25:08 -04:00
{
2017-03-07 00:09:37 -05:00
//load hotbars
//Calculate stats
//Calculate hp/mp
//Get Potenciel ??????
2017-09-27 18:10:22 -05:00
2017-03-07 00:09:37 -05:00
//Set HP/MP/TP PARAMS
//Set mainskill and level
2017-09-27 18:10:22 -05:00
2017-03-07 00:09:37 -05:00
//Set Parameters
//Set current EXP
//Set Hotbar Commands 1
//Set Hotbar Commands 2
//Set Hotbar Commands 3
//Check if bonus point available... set
//Set rested EXP
charaWork . parameterSave . state_mainSkill [ 0 ] = classId ;
charaWork . parameterSave . state_mainSkillLevel = charaWork . battleSave . skillLevel [ classId - 1 ] ;
playerWork . restBonusExpRate = 0.0f ;
2017-08-29 09:00:09 -05:00
for ( int i = charaWork . commandBorder ; i < charaWork . command . Length ; i + + )
{
charaWork . command [ i ] = 0 ;
charaWork . commandCategory [ i ] = 0 ;
}
2017-03-07 00:09:37 -05:00
2017-06-27 13:52:47 -04:00
ActorPropertyPacketUtil propertyBuilder = new ActorPropertyPacketUtil ( "charaWork/stateForAll" , this ) ;
2017-03-07 00:09:37 -05:00
propertyBuilder . AddProperty ( "charaWork.parameterSave.state_mainSkill[0]" ) ;
propertyBuilder . AddProperty ( "charaWork.parameterSave.state_mainSkillLevel" ) ;
propertyBuilder . NewTarget ( "playerWork/expBonus" ) ;
propertyBuilder . AddProperty ( "playerWork.restBonusExpRate" ) ;
2017-09-30 20:04:45 -05:00
propertyBuilder . NewTarget ( "charaWork/battleStateForSelf" ) ;
2018-10-08 15:11:43 -04:00
propertyBuilder . AddProperty ( String . Format ( "charaWork.battleSave.skillPoint[{0}]" , classId - 1 ) ) ;
2017-08-22 14:50:53 -05:00
Database . LoadHotbar ( this ) ;
var time = Utils . UnixTimeStampUTC ( ) ;
for ( int i = charaWork . commandBorder ; i < charaWork . command . Length ; i + + )
{
if ( charaWork . command [ i ] ! = 0 )
{
charaWork . parameterSave . commandSlot_recastTime [ i - charaWork . commandBorder ] = time + charaWork . parameterTemp . maxCommandRecastTime [ i - charaWork . commandBorder ] ;
}
}
UpdateHotbar ( ) ;
2017-03-07 00:09:37 -05:00
List < SubPacket > packets = propertyBuilder . Done ( ) ;
foreach ( SubPacket packet in packets )
BroadcastPacket ( packet , true ) ;
Database . SavePlayerCurrentClass ( this ) ;
2017-08-26 04:08:26 +01:00
RecalculateStats ( ) ;
2017-03-07 00:09:37 -05:00
}
2018-04-07 15:34:11 -04:00
public void UpdateClassLevel ( byte classId , short level )
{
Database . PlayerCharacterUpdateClassLevel ( this , classId , level ) ;
charaWork . battleSave . skillLevel [ classId - 1 ] = level ;
ActorPropertyPacketUtil propertyBuilder = new ActorPropertyPacketUtil ( "charaWork/exp" , this ) ;
propertyBuilder . AddProperty ( String . Format ( "charaWork.battleSave.skillLevel[{0}]" , classId - 1 ) ) ;
List < SubPacket > packets = propertyBuilder . Done ( ) ;
QueuePackets ( packets ) ;
}
2017-03-07 00:09:37 -05:00
public void GraphicChange ( int slot , InventoryItem invItem )
{
if ( invItem = = null )
appearanceIds [ slot ] = 0 ;
else
{
2017-06-24 14:12:52 -04:00
ItemData item = Server . GetItemGamedata ( invItem . itemId ) ;
2017-08-26 13:53:23 -04:00
2017-03-07 00:09:37 -05:00
if ( item is EquipmentItem )
{
EquipmentItem eqItem = ( EquipmentItem ) item ;
uint mixedVariantId ;
if ( eqItem . graphicsWeaponId = = 0 )
mixedVariantId = ( ( eqItem . graphicsVariantId & 0x1F ) < < 5 ) | eqItem . graphicsColorId ;
else
mixedVariantId = eqItem . graphicsVariantId ;
uint graphicId =
( eqItem . graphicsWeaponId & 0x3FF ) < < 20 |
( eqItem . graphicsEquipmentId & 0x3FF ) < < 10 |
( mixedVariantId & 0x3FF ) ;
appearanceIds [ slot ] = graphicId ;
}
2017-07-09 11:39:17 -04:00
//Handle offhand
if ( slot = = MAINHAND & & item is WeaponItem )
{
WeaponItem wpItem = ( WeaponItem ) item ;
uint graphicId =
( wpItem . graphicsOffhandWeaponId & 0x3FF ) < < 20 |
( wpItem . graphicsOffhandEquipmentId & 0x3FF ) < < 10 |
( wpItem . graphicsOffhandVariantId & 0x3FF ) ;
appearanceIds [ SetActorAppearancePacket . OFFHAND ] = graphicId ;
}
2017-01-29 11:07:28 -05:00
}
2017-03-07 00:09:37 -05:00
Database . SavePlayerAppearance ( this ) ;
2017-06-27 13:52:47 -04:00
BroadcastPacket ( CreateAppearancePacket ( ) , true ) ;
2017-06-14 22:24:09 -04:00
}
2017-03-07 00:09:37 -05:00
2017-11-11 10:56:15 -05:00
public void SetRepairRequest ( byte type )
2017-03-07 00:09:37 -05:00
{
2017-11-11 10:56:15 -05:00
charaWork . eventSave . repairType = type ;
ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil ( "charaWork/bazaar" , this ) ;
propPacketUtil . AddProperty ( "charaWork.eventSave.repairType" ) ;
QueuePackets ( propPacketUtil . Done ( ) ) ;
2017-03-07 00:09:37 -05:00
}
2017-12-10 13:38:53 -05:00
public void CheckBazaarFlags ( bool noUpdate = false )
2017-11-11 10:56:15 -05:00
{
bool isDealing = false , isRepairing = false , seekingItem = false ;
2018-04-07 14:48:43 -04:00
lock ( GetItemPackage ( ItemPackage . BAZAAR ) )
2017-11-11 10:56:15 -05:00
{
2018-04-07 14:48:43 -04:00
foreach ( InventoryItem item in GetItemPackage ( ItemPackage . BAZAAR ) . GetRawList ( ) )
2017-11-11 10:56:15 -05:00
{
if ( item = = null )
break ;
2017-11-11 17:05:07 -05:00
if ( item . GetBazaarMode ( ) = = InventoryItem . TYPE_SINGLE | | item . GetBazaarMode ( ) = = InventoryItem . TYPE_MULTI | | item . GetBazaarMode ( ) = = InventoryItem . TYPE_STACK )
2017-11-11 10:56:15 -05:00
isDealing = true ;
if ( item . GetBazaarMode ( ) = = InventoryItem . TYPE_SEEK_REPAIR )
isRepairing = true ;
if ( item . GetBazaarMode ( ) = = InventoryItem . TYPE_SEEK_ITEM )
2017-12-10 23:52:10 -05:00
isDealing = true ;
2017-11-11 10:56:15 -05:00
if ( isDealing & & isRepairing & & seekingItem )
break ;
}
}
2017-12-10 13:38:53 -05:00
bool doUpdate = false ;
2017-12-10 23:52:10 -05:00
ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil ( "charaWork/bazaar" , this ) ;
2017-12-10 22:53:37 -05:00
if ( charaWork . eventTemp . bazaarRetail ! = isDealing )
{
charaWork . eventTemp . bazaarRetail = isDealing ;
propPacketUtil . AddProperty ( "charaWork.eventTemp.bazaarRetail" ) ;
2017-12-10 13:38:53 -05:00
doUpdate = true ;
2017-12-10 22:53:37 -05:00
}
2017-12-10 13:38:53 -05:00
2017-12-10 22:53:37 -05:00
if ( charaWork . eventTemp . bazaarRepair ! = isRepairing )
2017-12-10 13:38:53 -05:00
{
2017-12-10 22:53:37 -05:00
charaWork . eventTemp . bazaarRepair = isRepairing ;
2017-12-10 13:38:53 -05:00
propPacketUtil . AddProperty ( "charaWork.eventTemp.bazaarRepair" ) ;
2017-12-10 22:53:37 -05:00
doUpdate = true ;
}
2018-04-07 14:48:43 -04:00
if ( charaWork . eventTemp . bazaarMateria ! = ( GetItemPackage ( ItemPackage . MELDREQUEST ) . GetCount ( ) ! = 0 ) )
2017-12-10 22:53:37 -05:00
{
2018-04-07 14:48:43 -04:00
charaWork . eventTemp . bazaarMateria = GetItemPackage ( ItemPackage . MELDREQUEST ) . GetCount ( ) ! = 0 ;
2017-12-10 13:38:53 -05:00
propPacketUtil . AddProperty ( "charaWork.eventTemp.bazaarMateria" ) ;
2017-12-10 22:53:37 -05:00
doUpdate = true ;
2017-12-10 13:38:53 -05:00
}
2017-12-10 22:53:37 -05:00
if ( ! noUpdate & & doUpdate )
BroadcastPackets ( propPacketUtil . Done ( ) , true ) ;
2017-11-11 17:05:07 -05:00
}
2017-03-07 00:09:37 -05:00
2016-08-21 18:16:54 -04:00
public int GetCurrentGil ( )
{
2017-11-11 17:05:07 -05:00
if ( HasItem ( 1000001 ) )
2018-04-07 14:48:43 -04:00
return GetItemPackage ( ItemPackage . CURRENCY_CRYSTALS ) . GetItemByCatelogId ( 1000001 ) . quantity ;
2016-08-21 18:16:54 -04:00
else
return 0 ;
}
2017-03-07 00:09:37 -05:00
public Actor GetActorInInstance ( uint actorId )
{
foreach ( Actor a in playerSession . actorInstanceList )
2017-01-29 11:07:28 -05:00
{
2017-03-07 00:09:37 -05:00
if ( a . actorId = = actorId )
return a ;
2017-01-29 11:07:28 -05:00
}
2017-03-07 00:09:37 -05:00
return null ;
}
public void SetZoneChanging ( bool flag )
{
isZoneChanging = flag ;
}
public bool IsInZoneChange ( )
{
return isZoneChanging ;
}
2019-06-02 16:57:46 -04:00
public ReferencedItemPackage GetEquipment ( )
2017-03-07 00:09:37 -05:00
{
return equipment ;
}
public byte GetInitialTown ( )
{
return playerWork . initialTown ;
}
2017-05-01 22:30:43 -04:00
public uint GetHomePoint ( )
{
return homepoint ;
}
public byte GetHomePointInn ( )
{
return homepointInn ;
}
public void SetHomePoint ( uint aetheryteId )
{
homepoint = aetheryteId ;
Database . SavePlayerHomePoints ( this ) ;
}
public void SetHomePointInn ( byte townId )
{
homepointInn = townId ;
Database . SavePlayerHomePoints ( this ) ;
}
public bool HasAetheryteNodeUnlocked ( uint aetheryteId )
{
if ( aetheryteId ! = 0 )
return true ;
else
return false ;
}
2017-03-07 00:09:37 -05:00
public int GetFreeQuestSlot ( )
{
for ( int i = 0 ; i < questScenario . Length ; i + + )
2017-01-29 11:07:28 -05:00
{
2017-03-07 00:09:37 -05:00
if ( questScenario [ i ] = = null )
return i ;
}
return - 1 ;
}
2017-06-24 12:07:27 -04:00
public int GetFreeGuildleveSlot ( )
{
2017-06-25 23:35:55 -04:00
for ( int i = 0 ; i < work . guildleveId . Length ; i + + )
2017-06-24 12:07:27 -04:00
{
2017-06-25 23:35:55 -04:00
if ( work . guildleveId [ i ] = = 0 )
2017-06-24 12:07:27 -04:00
return i ;
}
return - 1 ;
}
2017-04-02 18:44:47 -04:00
//For Lua calls, cause MoonSharp goes retard with uint
public void AddQuest ( int id , bool isSilent = false )
{
AddQuest ( ( uint ) id , isSilent ) ;
}
public void CompleteQuest ( int id )
{
CompleteQuest ( ( uint ) id ) ;
}
public bool HasQuest ( int id )
{
return HasQuest ( ( uint ) id ) ;
}
public Quest GetQuest ( int id )
{
return GetQuest ( ( uint ) id ) ;
}
public bool IsQuestCompleted ( int id )
{
return IsQuestCompleted ( ( uint ) id ) ;
}
public bool CanAcceptQuest ( int id )
{
return CanAcceptQuest ( ( uint ) id ) ;
}
//For Lua calls, cause MoonSharp goes retard with uint
2017-06-24 12:07:27 -04:00
public void AddGuildleve ( uint id )
{
int freeSlot = GetFreeGuildleveSlot ( ) ;
if ( freeSlot = = - 1 )
return ;
2017-06-25 23:35:55 -04:00
work . guildleveId [ freeSlot ] = ( ushort ) id ;
2017-06-24 12:07:27 -04:00
Database . SaveGuildleve ( this , id , freeSlot ) ;
SendGuildleveClientUpdate ( freeSlot ) ;
}
2017-06-25 23:02:20 -04:00
public void MarkGuildleve ( uint id , bool abandoned , bool completed )
{
if ( HasGuildleve ( id ) )
{
2017-06-25 23:35:55 -04:00
for ( int i = 0 ; i < work . guildleveId . Length ; i + + )
2017-06-25 23:02:20 -04:00
{
2017-06-25 23:35:55 -04:00
if ( work . guildleveId [ i ] = = id )
2017-06-25 23:02:20 -04:00
{
2017-06-25 23:35:55 -04:00
work . guildleveChecked [ i ] = completed ;
work . guildleveDone [ i ] = abandoned ;
2017-06-25 23:02:20 -04:00
Database . MarkGuildleve ( this , id , abandoned , completed ) ;
2017-06-25 23:35:55 -04:00
SendGuildleveMarkClientUpdate ( i ) ;
2017-06-25 23:02:20 -04:00
}
}
}
}
2017-06-24 12:07:27 -04:00
public void RemoveGuildleve ( uint id )
{
if ( HasGuildleve ( id ) )
{
2017-06-25 23:35:55 -04:00
for ( int i = 0 ; i < work . guildleveId . Length ; i + + )
2017-06-24 12:07:27 -04:00
{
2017-06-25 23:35:55 -04:00
if ( work . guildleveId [ i ] = = id )
2017-06-24 12:07:27 -04:00
{
Database . RemoveGuildleve ( this , id ) ;
2017-06-25 23:35:55 -04:00
work . guildleveId [ i ] = 0 ;
2017-06-24 12:07:27 -04:00
SendGuildleveClientUpdate ( i ) ;
break ;
}
}
}
}
2017-03-20 23:31:11 -04:00
public void AddQuest ( uint id , bool isSilent = false )
2016-06-24 20:52:30 +01:00
{
2017-03-07 00:09:37 -05:00
Actor actor = Server . GetStaticActors ( ( 0xA0F00000 | id ) ) ;
2017-03-20 23:31:11 -04:00
AddQuest ( actor . actorName , isSilent ) ;
2017-03-07 00:09:37 -05:00
}
2017-03-20 23:31:11 -04:00
public void AddQuest ( string name , bool isSilent = false )
2017-03-07 00:09:37 -05:00
{
Actor actor = Server . GetStaticActors ( name ) ;
if ( actor = = null )
return ;
uint id = actor . actorId ;
int freeSlot = GetFreeQuestSlot ( ) ;
if ( freeSlot = = - 1 )
return ;
playerWork . questScenario [ freeSlot ] = id ;
2017-04-04 01:42:34 -04:00
questScenario [ freeSlot ] = new Quest ( this , playerWork . questScenario [ freeSlot ] , name , null , 0 , 0 ) ;
2017-03-07 00:09:37 -05:00
Database . SaveQuest ( this , questScenario [ freeSlot ] ) ;
SendQuestClientUpdate ( freeSlot ) ;
2017-03-20 23:31:11 -04:00
if ( ! isSilent )
{
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 25224 , 0x20 , ( object ) questScenario [ freeSlot ] . GetQuestId ( ) ) ;
questScenario [ freeSlot ] . NextPhase ( 0 ) ;
}
2017-04-02 18:44:47 -04:00
}
2017-03-20 23:31:11 -04:00
public void CompleteQuest ( uint id )
{
Actor actor = Server . GetStaticActors ( ( 0xA0F00000 | id ) ) ;
CompleteQuest ( actor . actorName ) ;
}
public void CompleteQuest ( string name )
{
Actor actor = Server . GetStaticActors ( name ) ;
if ( actor = = null )
return ;
uint id = actor . actorId ;
if ( HasQuest ( id ) )
{
2017-04-02 23:50:51 -04:00
Database . CompleteQuest ( playerSession . GetActor ( ) , id ) ;
2017-03-20 23:31:11 -04:00
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 25086 , 0x20 , ( object ) GetQuest ( id ) . GetQuestId ( ) ) ;
RemoveQuest ( id ) ;
}
2017-03-07 00:09:37 -05:00
}
2017-04-04 01:10:26 -04:00
//TODO: Add checks for you being in an instance or main scenario
public void AbandonQuest ( uint id )
{
Quest quest = GetQuest ( id ) ;
RemoveQuestByQuestId ( id ) ;
quest . DoAbandon ( ) ;
}
2017-04-02 23:50:51 -04:00
public void RemoveQuestByQuestId ( uint id )
{
RemoveQuest ( ( 0xA0F00000 | id ) ) ;
}
2017-03-07 00:09:37 -05:00
public void RemoveQuest ( uint id )
{
if ( HasQuest ( id ) )
2016-06-24 20:52:30 +01:00
{
2017-03-07 00:09:37 -05:00
for ( int i = 0 ; i < questScenario . Length ; i + + )
{
if ( questScenario [ i ] ! = null & & questScenario [ i ] . actorId = = id )
{
2017-04-02 23:50:51 -04:00
Database . RemoveQuest ( this , questScenario [ i ] . actorId ) ;
2017-03-20 23:31:11 -04:00
questScenario [ i ] = null ;
2017-03-20 23:37:05 -04:00
playerWork . questScenario [ i ] = 0 ;
2017-03-07 00:09:37 -05:00
SendQuestClientUpdate ( i ) ;
break ;
}
}
}
}
2016-06-24 20:52:30 +01:00
2017-03-07 00:09:37 -05:00
public void ReplaceQuest ( uint oldId , uint newId )
{
if ( HasQuest ( oldId ) )
{
for ( int i = 0 ; i < questScenario . Length ; i + + )
{
if ( questScenario [ i ] ! = null & & questScenario [ i ] . GetQuestId ( ) = = oldId )
{
Actor actor = Server . GetStaticActors ( ( 0xA0F00000 | newId ) ) ;
playerWork . questScenario [ i ] = ( 0xA0F00000 | newId ) ;
2017-04-04 01:42:34 -04:00
questScenario [ i ] = new Quest ( this , playerWork . questScenario [ i ] , actor . actorName , null , 0 , 0 ) ;
2017-03-07 00:09:37 -05:00
Database . SaveQuest ( this , questScenario [ i ] ) ;
SendQuestClientUpdate ( i ) ;
break ;
}
}
2016-06-24 20:52:30 +01:00
}
2017-03-07 00:09:37 -05:00
}
2017-03-28 18:03:16 -04:00
public bool CanAcceptQuest ( string name )
{
if ( ! IsQuestCompleted ( name ) & & ! HasQuest ( name ) )
return true ;
else
return false ;
}
public bool CanAcceptQuest ( uint id )
{
Actor actor = Server . GetStaticActors ( ( 0xA0F00000 | id ) ) ;
return CanAcceptQuest ( actor . actorName ) ;
}
2017-04-02 23:50:51 -04:00
public bool IsQuestCompleted ( string questName )
2017-03-28 18:03:16 -04:00
{
2017-04-02 23:50:51 -04:00
Actor actor = Server . GetStaticActors ( questName ) ;
return IsQuestCompleted ( actor . actorId ) ;
2017-03-28 18:03:16 -04:00
}
2017-04-02 23:50:51 -04:00
public bool IsQuestCompleted ( uint questId )
2017-03-28 18:03:16 -04:00
{
2017-04-02 23:50:51 -04:00
return Database . IsQuestCompleted ( this , 0xFFFFF & questId ) ;
2017-03-28 18:03:16 -04:00
}
2017-03-07 00:09:37 -05:00
public Quest GetQuest ( uint id )
{
for ( int i = 0 ; i < questScenario . Length ; i + + )
2016-06-24 20:52:30 +01:00
{
2017-03-07 00:09:37 -05:00
if ( questScenario [ i ] ! = null & & questScenario [ i ] . actorId = = ( 0xA0F00000 | id ) )
return questScenario [ i ] ;
2016-06-24 20:52:30 +01:00
}
2017-01-02 14:35:11 -05:00
2017-03-07 00:09:37 -05:00
return null ;
2016-12-03 12:19:59 -05:00
}
2017-03-07 00:09:37 -05:00
public Quest GetQuest ( string name )
2016-12-03 12:19:59 -05:00
{
2017-03-07 00:09:37 -05:00
for ( int i = 0 ; i < questScenario . Length ; i + + )
{
if ( questScenario [ i ] ! = null & & questScenario [ i ] . actorName . ToLower ( ) . Equals ( name . ToLower ( ) ) )
return questScenario [ i ] ;
}
2016-12-03 12:19:59 -05:00
2017-03-07 00:09:37 -05:00
return null ;
}
2016-12-03 12:19:59 -05:00
2017-03-07 00:09:37 -05:00
public bool HasQuest ( string name )
{
for ( int i = 0 ; i < questScenario . Length ; i + + )
{
if ( questScenario [ i ] ! = null & & questScenario [ i ] . actorName . ToLower ( ) . Equals ( name . ToLower ( ) ) )
return true ;
}
2016-12-20 19:17:50 -05:00
2017-03-07 00:09:37 -05:00
return false ;
}
2016-12-03 12:19:59 -05:00
2017-03-07 00:09:37 -05:00
public bool HasQuest ( uint id )
2017-01-29 11:07:28 -05:00
{
2017-03-07 00:09:37 -05:00
for ( int i = 0 ; i < questScenario . Length ; i + + )
{
if ( questScenario [ i ] ! = null & & questScenario [ i ] . actorId = = ( 0xA0F00000 | id ) )
return true ;
}
return false ;
}
2017-06-24 12:07:27 -04:00
public bool HasGuildleve ( uint id )
{
2017-06-25 23:35:55 -04:00
for ( int i = 0 ; i < work . guildleveId . Length ; i + + )
2017-06-24 12:07:27 -04:00
{
2017-06-25 23:35:55 -04:00
if ( work . guildleveId [ i ] = = id )
2017-06-24 12:07:27 -04:00
return true ;
}
return false ;
}
2017-03-07 00:09:37 -05:00
public int GetQuestSlot ( uint id )
{
for ( int i = 0 ; i < questScenario . Length ; i + + )
{
if ( questScenario [ i ] ! = null & & questScenario [ i ] . actorId = = ( 0xA0F00000 | id ) )
return i ;
}
return - 1 ;
}
2017-04-09 14:01:15 -04:00
public void SetNpcLS ( uint npcLSId , uint state )
{
bool isCalling , isExtra ;
isCalling = isExtra = false ;
switch ( state )
{
case NPCLS_INACTIVE :
if ( playerWork . npcLinkshellChatExtra [ npcLSId ] = = true & & playerWork . npcLinkshellChatCalling [ npcLSId ] = = false )
return ;
isExtra = true ;
break ;
case NPCLS_ACTIVE :
if ( playerWork . npcLinkshellChatExtra [ npcLSId ] = = false & & playerWork . npcLinkshellChatCalling [ npcLSId ] = = true )
return ;
isCalling = true ;
break ;
case NPCLS_ALERT :
if ( playerWork . npcLinkshellChatExtra [ npcLSId ] = = true & & playerWork . npcLinkshellChatCalling [ npcLSId ] = = true )
return ;
isExtra = isCalling = true ;
break ;
}
2017-04-09 12:48:27 -04:00
playerWork . npcLinkshellChatExtra [ npcLSId ] = isExtra ;
playerWork . npcLinkshellChatCalling [ npcLSId ] = isCalling ;
Database . SaveNpcLS ( this , npcLSId , isCalling , isExtra ) ;
2017-06-27 13:52:47 -04:00
ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil ( "playerWork/npcLinkshellChat" , this ) ;
2017-04-09 12:48:27 -04:00
propPacketUtil . AddProperty ( String . Format ( "playerWork.npcLinkshellChatExtra[{0}]" , npcLSId ) ) ;
propPacketUtil . AddProperty ( String . Format ( "playerWork.npcLinkshellChatCalling[{0}]" , npcLSId ) ) ;
QueuePackets ( propPacketUtil . Done ( ) ) ;
}
2017-03-07 00:09:37 -05:00
private void SendQuestClientUpdate ( int slot )
{
2017-06-27 13:52:47 -04:00
ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil ( "playerWork/journal" , this ) ;
2017-03-07 00:09:37 -05:00
propPacketUtil . AddProperty ( String . Format ( "playerWork.questScenario[{0}]" , slot ) ) ;
QueuePackets ( propPacketUtil . Done ( ) ) ;
}
2017-06-24 12:07:27 -04:00
private void SendGuildleveClientUpdate ( int slot )
{
2017-06-27 13:52:47 -04:00
ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil ( "work/guildleve" , this ) ;
2017-06-25 23:35:55 -04:00
propPacketUtil . AddProperty ( String . Format ( "work.guildleveId[{0}]" , slot ) ) ;
2017-06-24 12:07:27 -04:00
QueuePackets ( propPacketUtil . Done ( ) ) ;
}
2017-06-25 23:02:20 -04:00
private void SendGuildleveMarkClientUpdate ( int slot )
{
2017-06-27 13:52:47 -04:00
ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil ( "work/guildleve" , this ) ;
2017-06-25 23:02:20 -04:00
propPacketUtil . AddProperty ( String . Format ( "work.guildleveDone[{0}]" , slot ) ) ;
propPacketUtil . AddProperty ( String . Format ( "work.guildleveChecked[{0}]" , slot ) ) ;
QueuePackets ( propPacketUtil . Done ( ) ) ;
}
2017-08-26 12:33:37 -04:00
public void SendStartCastbar ( uint commandId , uint endTime )
{
playerWork . castCommandClient = commandId ;
playerWork . castEndClient = endTime ;
ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil ( "playerWork/castState" , this ) ;
propPacketUtil . AddProperty ( "playerWork.castEndClient" ) ;
propPacketUtil . AddProperty ( "playerWork.castCommandClient" ) ;
QueuePackets ( propPacketUtil . Done ( ) ) ;
}
public void SendEndCastbar ( )
{
playerWork . castCommandClient = 0 ;
playerWork . castEndClient = 0 ;
ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil ( "playerWork/castState" , this ) ;
propPacketUtil . AddProperty ( "playerWork.castCommandClient" ) ;
QueuePackets ( propPacketUtil . Done ( ) ) ;
}
2017-01-29 11:07:28 -05:00
public void SetLoginDirector ( Director director )
{
if ( ownedDirectors . Contains ( director ) )
loginInitDirector = director ;
2017-03-07 00:09:37 -05:00
}
2017-06-24 12:07:27 -04:00
public void AddDirector ( Director director , bool spawnImmediatly = false )
2017-01-29 11:07:28 -05:00
{
if ( ! ownedDirectors . Contains ( director ) )
{
ownedDirectors . Add ( director ) ;
2017-06-24 15:31:42 -04:00
director . AddMember ( this ) ;
2017-03-07 00:09:37 -05:00
}
}
2017-04-15 16:33:56 -04:00
public void SendDirectorPackets ( Director director )
{
2017-06-27 21:40:49 -04:00
QueuePackets ( director . GetSpawnPackets ( ) ) ;
QueuePackets ( director . GetInitPackets ( ) ) ;
2017-04-15 16:33:56 -04:00
}
2017-01-29 11:07:28 -05:00
public void RemoveDirector ( Director director )
{
2017-06-25 14:25:54 -04:00
if ( ownedDirectors . Contains ( director ) )
2017-01-29 11:07:28 -05:00
{
2017-06-27 13:52:47 -04:00
QueuePacket ( RemoveActorPacket . BuildPacket ( director . actorId ) ) ;
2017-01-29 11:07:28 -05:00
ownedDirectors . Remove ( director ) ;
2017-06-24 15:31:42 -04:00
director . RemoveMember ( this ) ;
2017-01-29 11:07:28 -05:00
}
2017-03-07 00:09:37 -05:00
}
2019-01-29 00:02:09 -05:00
2017-06-25 14:52:32 -04:00
public GuildleveDirector GetGuildleveDirector ( )
2017-06-25 14:25:54 -04:00
{
foreach ( Director d in ownedDirectors )
{
if ( d is GuildleveDirector )
2017-06-25 14:52:32 -04:00
return ( GuildleveDirector ) d ;
2017-06-25 14:25:54 -04:00
}
return null ;
}
2017-03-07 00:09:37 -05:00
public Director GetDirector ( string directorName )
{
2017-01-29 11:07:28 -05:00
foreach ( Director d in ownedDirectors )
{
2017-03-07 00:09:37 -05:00
if ( d . GetScriptPath ( ) . Equals ( directorName ) )
2017-01-29 11:07:28 -05:00
return d ;
}
2017-03-07 00:09:37 -05:00
return null ;
2017-01-29 11:07:28 -05:00
}
public Director GetDirector ( uint id )
{
foreach ( Director d in ownedDirectors )
{
if ( d . actorId = = id )
return d ;
}
return null ;
2017-03-07 00:09:37 -05:00
}
public void ExaminePlayer ( Actor examinee )
{
Player toBeExamined ;
if ( examinee is Player )
toBeExamined = ( Player ) examinee ;
else
return ;
2019-06-02 16:57:46 -04:00
QueuePacket ( InventoryBeginChangePacket . BuildPacket ( toBeExamined . actorId , true ) ) ;
toBeExamined . GetEquipment ( ) . SendUpdateAsItemPackage ( this , ItemPackage . MAXSIZE_EQUIPMENT_OTHERPLAYER , ItemPackage . EQUIPMENT_OTHERPLAYER ) ;
2017-06-27 13:52:47 -04:00
QueuePacket ( InventoryEndChangePacket . BuildPacket ( toBeExamined . actorId ) ) ;
2019-06-02 16:57:46 -04:00
}
2017-09-05 12:37:23 -04:00
2017-03-19 12:35:21 -04:00
public void SendDataPacket ( params object [ ] parameters )
2017-03-07 00:09:37 -05:00
{
List < LuaParam > lParams = LuaUtils . CreateLuaParamList ( parameters ) ;
2017-08-26 13:53:23 -04:00
SubPacket spacket = GenericDataPacket . BuildPacket ( actorId , lParams ) ;
2017-03-07 00:09:37 -05:00
spacket . DebugPrintSubPacket ( ) ;
QueuePacket ( spacket ) ;
}
public void StartEvent ( Actor owner , EventStartPacket start )
{
2018-04-07 14:24:33 -04:00
currentEventOwner = start . scriptOwnerActorID ;
currentEventName = start . triggerName ;
2017-03-13 14:06:57 -04:00
LuaEngine . GetInstance ( ) . EventStarted ( this , owner , start ) ;
2017-03-07 00:09:37 -05:00
}
public void UpdateEvent ( EventUpdatePacket update )
{
2018-04-07 14:04:22 -04:00
LuaEngine . GetInstance ( ) . OnEventUpdate ( this , update . luaParams ) ;
}
2017-03-07 00:09:37 -05:00
public void KickEvent ( Actor actor , string conditionName , params object [ ] parameters )
{
if ( actor = = null )
return ;
List < LuaParam > lParams = LuaUtils . CreateLuaParamList ( parameters ) ;
2017-12-17 15:25:42 -05:00
SubPacket spacket = KickEventPacket . BuildPacket ( actorId , actor . actorId , 0x75dc1705 , conditionName , lParams ) ;
2017-10-08 12:26:22 -04:00
spacket . DebugPrintSubPacket ( ) ;
QueuePacket ( spacket ) ;
}
public void KickEventSpecial ( Actor actor , uint unknown , string conditionName , params object [ ] parameters )
{
if ( actor = = null )
return ;
List < LuaParam > lParams = LuaUtils . CreateLuaParamList ( parameters ) ;
SubPacket spacket = KickEventPacket . BuildPacket ( actorId , actor . actorId , unknown , conditionName , lParams ) ;
2017-03-07 00:09:37 -05:00
spacket . DebugPrintSubPacket ( ) ;
QueuePacket ( spacket ) ;
}
public void SetEventStatus ( Actor actor , string conditionName , bool enabled , byte unknown )
{
2017-06-27 13:52:47 -04:00
QueuePacket ( packets . send . actor . events . SetEventStatus . BuildPacket ( actor . actorId , enabled , unknown , conditionName ) ) ;
2018-04-07 14:04:22 -04:00
}
2017-03-07 00:09:37 -05:00
public void RunEventFunction ( string functionName , params object [ ] parameters )
{
List < LuaParam > lParams = LuaUtils . CreateLuaParamList ( parameters ) ;
SubPacket spacket = RunEventFunctionPacket . BuildPacket ( actorId , currentEventOwner , currentEventName , functionName , lParams ) ;
spacket . DebugPrintSubPacket ( ) ;
QueuePacket ( spacket ) ;
}
public void EndEvent ( )
{
SubPacket p = EndEventPacket . BuildPacket ( actorId , currentEventOwner , currentEventName ) ;
p . DebugPrintSubPacket ( ) ;
QueuePacket ( p ) ;
currentEventOwner = 0 ;
currentEventName = "" ;
currentEventRunning = null ;
}
2017-10-01 12:31:45 -04:00
2017-10-01 12:39:46 -04:00
public void BroadcastCountdown ( byte countdownLength , ulong syncTime )
2017-10-01 12:31:45 -04:00
{
2017-10-01 12:39:46 -04:00
BroadcastPacket ( StartCountdownPacket . BuildPacket ( actorId , countdownLength , syncTime , "Go!" ) , true ) ;
2017-10-01 12:31:45 -04:00
}
2017-03-07 00:09:37 -05:00
public void SendInstanceUpdate ( )
{
2017-03-20 21:51:43 -04:00
//Server.GetWorldManager().SeamlessCheck(this);
2017-03-07 00:09:37 -05:00
2016-07-31 23:00:38 -04:00
//Update Instance
2016-07-31 21:48:17 -04:00
List < Actor > aroundMe = new List < Actor > ( ) ;
2017-12-08 00:58:39 -06:00
if ( zone ! = null )
2017-06-14 22:24:09 -04:00
aroundMe . AddRange ( zone . GetActorsAroundActor ( this , 50 ) ) ;
2016-07-31 21:48:17 -04:00
if ( zone2 ! = null )
aroundMe . AddRange ( zone2 . GetActorsAroundActor ( this , 50 ) ) ;
2017-03-07 00:09:37 -05:00
playerSession . UpdateInstance ( aroundMe ) ;
}
2016-12-21 09:27:51 -05:00
public bool IsInParty ( )
{
return currentParty ! = null ;
2017-03-07 00:09:37 -05:00
}
2016-12-21 09:27:51 -05:00
public bool IsPartyLeader ( )
{
if ( IsInParty ( ) )
{
Party party = ( Party ) currentParty ;
return party . GetLeader ( ) = = actorId ;
}
else
return false ;
2016-12-21 21:49:50 -05:00
}
public void PartyOustPlayer ( uint actorId )
{
SubPacket oustPacket = PartyModifyPacket . BuildPacket ( playerSession , 1 , actorId ) ;
QueuePacket ( oustPacket ) ;
2017-03-07 00:09:37 -05:00
}
2016-12-21 18:02:50 -05:00
public void PartyOustPlayer ( string name )
{
SubPacket oustPacket = PartyModifyPacket . BuildPacket ( playerSession , 1 , name ) ;
QueuePacket ( oustPacket ) ;
2016-12-21 09:27:51 -05:00
}
public void PartyLeave ( )
{
2016-12-22 14:47:24 -05:00
SubPacket leavePacket = PartyLeavePacket . BuildPacket ( playerSession , false ) ;
QueuePacket ( leavePacket ) ;
2016-12-21 09:27:51 -05:00
}
public void PartyDisband ( )
{
2016-12-22 14:47:24 -05:00
SubPacket disbandPacket = PartyLeavePacket . BuildPacket ( playerSession , true ) ;
QueuePacket ( disbandPacket ) ;
2016-12-21 09:27:51 -05:00
}
2016-12-21 21:49:50 -05:00
public void PartyPromote ( uint actorId )
{
SubPacket promotePacket = PartyModifyPacket . BuildPacket ( playerSession , 0 , actorId ) ;
QueuePacket ( promotePacket ) ;
}
2016-12-21 18:02:50 -05:00
public void PartyPromote ( string name )
2016-12-21 09:27:51 -05:00
{
2016-12-21 18:02:50 -05:00
SubPacket promotePacket = PartyModifyPacket . BuildPacket ( playerSession , 0 , name ) ;
QueuePacket ( promotePacket ) ;
2017-03-07 00:09:37 -05:00
}
//A party member list packet came, set the party
2016-12-21 09:27:51 -05:00
public void SetParty ( Party group )
2016-12-20 19:17:50 -05:00
{
2018-05-28 16:28:44 -05:00
if ( group is Party & & currentParty ! = group )
2016-12-20 19:17:50 -05:00
{
RemoveFromCurrentPartyAndCleanup ( ) ;
currentParty = group ;
}
2017-03-07 00:09:37 -05:00
}
//Removes the player from the party and cleans it up if needed
2016-12-20 19:17:50 -05:00
public void RemoveFromCurrentPartyAndCleanup ( )
{
if ( currentParty = = null )
return ;
2016-12-21 09:27:51 -05:00
Party partyGroup = ( Party ) currentParty ;
for ( int i = 0 ; i < partyGroup . members . Count ; i + + )
2016-12-20 19:17:50 -05:00
{
2016-12-21 09:27:51 -05:00
if ( partyGroup . members [ i ] = = actorId )
2016-12-20 19:17:50 -05:00
{
2016-12-21 09:27:51 -05:00
partyGroup . members . RemoveAt ( i ) ;
2016-12-20 19:17:50 -05:00
break ;
}
}
//currentParty.members.Remove(this);
2016-12-21 09:27:51 -05:00
if ( partyGroup . members . Count = = 0 )
Server . GetWorldManager ( ) . NoMembersInParty ( ( Party ) currentParty ) ;
2018-02-15 13:20:46 -06:00
2016-12-20 19:17:50 -05:00
currentParty = null ;
2017-03-07 00:09:37 -05:00
}
2017-05-01 22:30:43 -04:00
2016-08-19 16:32:14 -05:00
public void IssueChocobo ( byte appearanceId , string nameResponse )
2016-08-19 14:40:43 -05:00
{
2016-08-19 16:32:14 -05:00
Database . IssuePlayerChocobo ( this , appearanceId , nameResponse ) ;
2016-08-19 14:40:43 -05:00
hasChocobo = true ;
chocoboAppearance = appearanceId ;
2016-08-19 16:32:14 -05:00
chocoboName = nameResponse ;
}
2016-08-21 18:16:54 -04:00
public void ChangeChocoboAppearance ( byte appearanceId )
{
Database . ChangePlayerChocoboAppearance ( this , appearanceId ) ;
chocoboAppearance = appearanceId ;
}
2019-05-04 20:13:29 -04:00
2017-09-09 10:54:40 -04:00
public Retainer SpawnMyRetainer ( Npc bell , int retainerIndex )
2017-09-05 12:37:23 -04:00
{
2017-09-09 14:11:35 -04:00
Retainer retainer = Database . LoadRetainer ( this , retainerIndex ) ;
2017-09-05 12:37:23 -04:00
float distance = ( float ) Math . Sqrt ( ( ( positionX - bell . positionX ) * ( positionX - bell . positionX ) ) + ( ( positionZ - bell . positionZ ) * ( positionZ - bell . positionZ ) ) ) ;
float posX = bell . positionX - ( ( - 1.0f * ( bell . positionX - positionX ) ) / distance ) ;
float posZ = bell . positionZ - ( ( - 1.0f * ( bell . positionZ - positionZ ) ) / distance ) ;
2017-09-09 14:11:35 -04:00
retainer . positionX = posX ;
retainer . positionY = positionY ;
retainer . positionZ = posZ ;
retainer . rotation = ( float ) Math . Atan2 ( positionX - posX , positionZ - posZ ) ;
2017-09-05 12:37:23 -04:00
2017-09-09 10:54:40 -04:00
retainerMeetingGroup = new RetainerMeetingRelationGroup ( 5555 , this , retainer ) ;
retainerMeetingGroup . SendGroupPackets ( playerSession ) ;
2017-09-05 12:37:23 -04:00
currentSpawnedRetainer = retainer ;
sentRetainerSpawn = false ;
2017-09-09 10:54:40 -04:00
return retainer ;
2017-09-05 12:37:23 -04:00
}
public void DespawnMyRetainer ( )
{
if ( currentSpawnedRetainer ! = null )
{
currentSpawnedRetainer = null ;
2017-09-09 10:54:40 -04:00
retainerMeetingGroup . SendDeletePacket ( playerSession ) ;
retainerMeetingGroup = null ;
2017-09-05 12:37:23 -04:00
}
}
2019-05-04 20:13:29 -04:00
2017-08-02 23:06:11 +01:00
public override void Update ( DateTime tick )
{
aiContainer . Update ( tick ) ;
statusEffects . Update ( tick ) ;
}
public override void PostUpdate ( DateTime tick , List < SubPacket > packets = null )
{
2017-09-05 05:05:25 +01:00
// todo: is this correct?
if ( this . playerSession . isUpdatesLocked )
return ;
2017-08-23 03:08:43 +01:00
// todo: should probably add another flag for battleTemp since all this uses reflection
packets = new List < SubPacket > ( ) ;
2017-08-31 05:56:43 +01:00
// we only want the latest update for the player
if ( ( updateFlags & ActorUpdateFlags . Position ) ! = 0 )
{
if ( positionUpdates . Count > 1 )
positionUpdates . RemoveRange ( 1 , positionUpdates . Count - 1 ) ;
}
2017-08-23 03:08:43 +01:00
if ( ( updateFlags & ActorUpdateFlags . HpTpMp ) ! = 0 )
{
2017-12-08 00:58:39 -06:00
var propPacketUtil = new ActorPropertyPacketUtil ( "charaWork/stateAtQuicklyForAll" , this ) ;
2017-08-23 03:08:43 +01:00
2017-08-31 05:56:43 +01:00
// todo: should this be using job as index?
2018-10-08 15:11:43 -04:00
propPacketUtil . AddProperty ( "charaWork.parameterSave.hp[0]" ) ;
propPacketUtil . AddProperty ( "charaWork.parameterSave.hpMax[0]" ) ;
propPacketUtil . AddProperty ( "charaWork.parameterSave.state_mainSkill[0]" ) ;
propPacketUtil . AddProperty ( "charaWork.parameterSave.state_mainSkillLevel" ) ;
2017-08-23 03:08:43 +01:00
packets . AddRange ( propPacketUtil . Done ( ) ) ;
}
2018-04-18 16:06:41 -05:00
if ( ( updateFlags & ActorUpdateFlags . Stats ) ! = 0 )
{
var propPacketUtil = new ActorPropertyPacketUtil ( "charaWork/battleParameter" , this ) ;
for ( uint i = 0 ; i < 35 ; i + + )
{
if ( GetMod ( i ) ! = charaWork . battleTemp . generalParameter [ i ] )
{
charaWork . battleTemp . generalParameter [ i ] = ( short ) GetMod ( i ) ;
2018-10-08 15:11:43 -04:00
propPacketUtil . AddProperty ( String . Format ( "charaWork.battleTemp.generalParameter[{0}]" , i ) ) ;
2018-04-18 16:06:41 -05:00
}
}
QueuePackets ( propPacketUtil . Done ( ) ) ;
}
2017-08-25 03:52:43 +01:00
base . PostUpdate ( tick , packets ) ;
2017-08-02 23:06:11 +01:00
}
2019-01-29 00:02:09 -05:00
public override void Die ( DateTime tick , CommandResultContainer actionContainer = null )
2017-08-02 23:06:11 +01:00
{
// todo: death timer
aiContainer . InternalDie ( tick , 60 ) ;
}
2017-08-22 14:50:53 -05:00
//Update commands and recast timers for the entire hotbar
public void UpdateHotbar ( )
2017-07-07 21:53:44 -05:00
{
List < ushort > slotsToUpdate = new List < ushort > ( ) ;
for ( ushort i = charaWork . commandBorder ; i < charaWork . commandBorder + 30 ; i + + )
{
slotsToUpdate . Add ( i ) ;
}
2017-08-22 14:50:53 -05:00
UpdateHotbar ( slotsToUpdate ) ;
}
2017-07-07 21:53:44 -05:00
2017-08-22 14:50:53 -05:00
//Updates the hotbar and recast timers for only certain hotbar slots
public void UpdateHotbar ( List < ushort > slotsToUpdate )
{
UpdateHotbarCommands ( slotsToUpdate ) ;
UpdateRecastTimers ( slotsToUpdate ) ;
2017-07-07 21:53:44 -05:00
}
2017-08-22 14:50:53 -05:00
//Update command ids for the passed in hotbar slots
public void UpdateHotbarCommands ( List < ushort > slotsToUpdate )
2017-07-07 21:53:44 -05:00
{
2017-07-27 03:58:42 +01:00
ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil ( "charaWork/command" , this ) ;
2017-07-07 21:53:44 -05:00
foreach ( ushort slot in slotsToUpdate )
{
2018-10-08 15:11:43 -04:00
propPacketUtil . AddProperty ( String . Format ( "charaWork.command[{0}]" , slot ) ) ;
propPacketUtil . AddProperty ( String . Format ( "charaWork.commandCategory[{0}]" , slot ) ) ;
2017-07-07 21:53:44 -05:00
}
2017-10-10 13:32:47 -05:00
propPacketUtil . NewTarget ( "charaWork/commandDetailForSelf" ) ;
2017-08-22 14:50:53 -05:00
//Enable or disable slots based on whether there is an ability in that slot
foreach ( ushort slot in slotsToUpdate )
2017-07-07 21:53:44 -05:00
{
2017-08-22 14:50:53 -05:00
charaWork . parameterSave . commandSlot_compatibility [ slot - charaWork . commandBorder ] = charaWork . command [ slot ] ! = 0 ;
2018-10-08 15:11:43 -04:00
propPacketUtil . AddProperty ( String . Format ( "charaWork.parameterSave.commandSlot_compatibility[{0}]" , slot - charaWork . commandBorder ) ) ;
2017-07-07 21:53:44 -05:00
}
2017-08-22 14:50:53 -05:00
QueuePackets ( propPacketUtil . Done ( ) ) ;
2017-10-10 13:32:47 -05:00
//QueuePackets(compatibiltyUtil.Done());
2017-08-22 14:50:53 -05:00
}
2017-07-07 21:53:44 -05:00
2017-08-22 14:50:53 -05:00
//Update recast timers for the passed in hotbar slots
public void UpdateRecastTimers ( List < ushort > slotsToUpdate )
{
2017-07-07 21:53:44 -05:00
ActorPropertyPacketUtil recastPacketUtil = new ActorPropertyPacketUtil ( "charaWork/commandDetailForSelf" , this ) ;
2017-08-22 14:50:53 -05:00
foreach ( ushort slot in slotsToUpdate )
2017-07-07 21:53:44 -05:00
{
2017-08-22 14:50:53 -05:00
recastPacketUtil . AddProperty ( String . Format ( "charaWork.parameterTemp.maxCommandRecastTime[{0}]" , slot - charaWork . commandBorder ) ) ;
recastPacketUtil . AddProperty ( String . Format ( "charaWork.parameterSave.commandSlot_recastTime[{0}]" , slot - charaWork . commandBorder ) ) ;
2017-07-07 21:53:44 -05:00
}
QueuePackets ( recastPacketUtil . Done ( ) ) ;
}
2017-09-27 18:10:22 -05:00
//Find the first open slot in classId's hotbar and equip an ability there.
public void EquipAbilityInFirstOpenSlot ( byte classId , uint commandId , bool printMessage = true )
{
//Find first open slot on class's hotbar slot, then call EquipAbility with that slot.
ushort hotbarSlot = 0 ;
//If the class we're equipping for is the current class, we can just look at charawork.command
if ( classId = = charaWork . parameterSave . state_mainSkill [ 0 ] )
hotbarSlot = FindFirstCommandSlotById ( 0 ) ;
//Otherwise, we need to check the database.
else
hotbarSlot = ( ushort ) ( Database . FindFirstCommandSlot ( this , classId ) + charaWork . commandBorder ) ;
EquipAbility ( classId , commandId , hotbarSlot , printMessage ) ;
}
//Add commandId to classId's hotbar at hotbarSlot.
//If classId is not the current class, do it in the database
2018-02-15 13:20:46 -06:00
//hotbarSlot starts at 32
2017-09-27 18:10:22 -05:00
public void EquipAbility ( byte classId , uint commandId , ushort hotbarSlot , bool printMessage = true )
{
var ability = Server . GetWorldManager ( ) . GetBattleCommand ( commandId ) ;
2018-02-15 13:20:46 -06:00
uint trueCommandId = 0xA0F00000 + commandId ;
2017-09-27 18:10:22 -05:00
ushort lowHotbarSlot = ( ushort ) ( hotbarSlot - charaWork . commandBorder ) ;
2018-02-15 13:20:46 -06:00
ushort maxRecastTime = ( ushort ) ( ability ! = null ? ability . maxRecastTimeSeconds : 5 ) ;
2017-09-27 18:10:22 -05:00
uint recastEnd = Utils . UnixTimeStampUTC ( ) + maxRecastTime ;
List < ushort > slotsToUpdate = new List < ushort > ( ) ;
2017-10-10 13:32:47 -05:00
Database . EquipAbility ( this , classId , ( ushort ) ( hotbarSlot - charaWork . commandBorder ) , commandId , recastEnd ) ;
2017-09-27 18:10:22 -05:00
//If the class we're equipping for is the current class (need to find out if state_mainSkill is supposed to change when you're a job)
//then equip the ability in charawork.commands and save in databse, otherwise just save in database
2018-05-27 14:51:39 -05:00
if ( classId = = GetCurrentClassOrJob ( ) )
2017-09-27 18:10:22 -05:00
{
charaWork . command [ hotbarSlot ] = trueCommandId ;
charaWork . commandCategory [ hotbarSlot ] = 1 ;
charaWork . parameterTemp . maxCommandRecastTime [ lowHotbarSlot ] = maxRecastTime ;
charaWork . parameterSave . commandSlot_recastTime [ lowHotbarSlot ] = recastEnd ;
slotsToUpdate . Add ( hotbarSlot ) ;
UpdateHotbar ( slotsToUpdate ) ;
}
if ( printMessage )
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 30603 , 0x20 , 0 , commandId ) ;
}
//Doesn't take a classId because the only way to swap abilities is through the ability equip widget oe /eaction, which only apply to current class
//hotbarSlot 1 and 2 are 32-indexed.
public void SwapAbilities ( ushort hotbarSlot1 , ushort hotbarSlot2 )
{
2018-02-15 13:20:46 -06:00
//0 indexed hotbar slots for saving to database and recast timers
2017-09-27 18:10:22 -05:00
uint lowHotbarSlot1 = ( ushort ) ( hotbarSlot1 - charaWork . commandBorder ) ;
uint lowHotbarSlot2 = ( ushort ) ( hotbarSlot2 - charaWork . commandBorder ) ;
//Store information about first command
uint commandId = charaWork . command [ hotbarSlot1 ] ;
uint recastEnd = charaWork . parameterSave . commandSlot_recastTime [ lowHotbarSlot1 ] ;
ushort recastMax = charaWork . parameterTemp . maxCommandRecastTime [ lowHotbarSlot1 ] ;
//Move second command's info to first hotbar slot
charaWork . command [ hotbarSlot1 ] = charaWork . command [ hotbarSlot2 ] ;
charaWork . parameterTemp . maxCommandRecastTime [ lowHotbarSlot1 ] = charaWork . parameterTemp . maxCommandRecastTime [ lowHotbarSlot2 ] ;
charaWork . parameterSave . commandSlot_recastTime [ lowHotbarSlot1 ] = charaWork . parameterSave . commandSlot_recastTime [ lowHotbarSlot2 ] ;
//Move first command's info to second slot
charaWork . command [ hotbarSlot2 ] = commandId ;
charaWork . parameterTemp . maxCommandRecastTime [ lowHotbarSlot2 ] = recastMax ;
charaWork . parameterSave . commandSlot_recastTime [ lowHotbarSlot2 ] = recastEnd ;
2018-02-15 13:20:46 -06:00
//Save changes to both slots
Database . EquipAbility ( this , GetCurrentClassOrJob ( ) , ( ushort ) ( lowHotbarSlot1 ) , 0xA0F00000 ^ charaWork . command [ hotbarSlot1 ] , charaWork . parameterSave . commandSlot_recastTime [ lowHotbarSlot1 ] ) ;
Database . EquipAbility ( this , GetCurrentClassOrJob ( ) , ( ushort ) ( lowHotbarSlot2 ) , 0xA0F00000 ^ charaWork . command [ hotbarSlot2 ] , charaWork . parameterSave . commandSlot_recastTime [ lowHotbarSlot2 ] ) ;
//Update slots on client
2017-09-27 18:10:22 -05:00
List < ushort > slotsToUpdate = new List < ushort > ( ) ;
slotsToUpdate . Add ( hotbarSlot1 ) ;
slotsToUpdate . Add ( hotbarSlot2 ) ;
UpdateHotbar ( slotsToUpdate ) ;
}
public void UnequipAbility ( ushort hotbarSlot , bool printMessage = true )
2017-08-29 09:00:09 -05:00
{
List < ushort > slotsToUpdate = new List < ushort > ( ) ;
ushort trueHotbarSlot = ( ushort ) ( hotbarSlot + charaWork . commandBorder - 1 ) ;
uint commandId = charaWork . command [ trueHotbarSlot ] ;
Database . UnequipAbility ( this , ( ushort ) ( trueHotbarSlot - charaWork . commandBorder ) ) ;
charaWork . command [ trueHotbarSlot ] = 0 ;
slotsToUpdate . Add ( trueHotbarSlot ) ;
2017-09-27 18:10:22 -05:00
if ( printMessage )
2018-02-15 13:20:46 -06:00
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 30604 , 0x20 , 0 , 0xA0F00000 ^ commandId ) ;
2017-08-29 09:00:09 -05:00
UpdateHotbar ( slotsToUpdate ) ;
2017-07-07 21:53:44 -05:00
}
//Finds the first hotbar slot with a given commandId.
//If the returned value is outside the hotbar, it indicates it wasn't found.
2017-09-27 18:10:22 -05:00
public ushort FindFirstCommandSlotById ( uint commandId )
2017-07-07 21:53:44 -05:00
{
2017-09-03 11:18:35 -05:00
if ( commandId ! = 0 )
commandId | = 0xA0F00000 ;
2017-07-07 21:53:44 -05:00
ushort firstSlot = ( ushort ) ( charaWork . commandBorder + 30 ) ;
for ( ushort i = charaWork . commandBorder ; i < charaWork . commandBorder + 30 ; i + + )
{
if ( charaWork . command [ i ] = = commandId )
{
firstSlot = i ;
break ;
}
}
return firstSlot ;
}
2017-08-31 05:56:43 +01:00
2018-02-15 13:20:46 -06:00
private void UpdateHotbarTimer ( uint commandId , uint recastTimeMs )
2017-08-31 05:56:43 +01:00
{
ushort slot = FindFirstCommandSlotById ( commandId ) ;
2018-02-15 13:20:46 -06:00
charaWork . parameterSave . commandSlot_recastTime [ slot - charaWork . commandBorder ] = Utils . UnixTimeStampUTC ( DateTime . Now . AddMilliseconds ( recastTimeMs ) ) ;
2017-08-31 05:56:43 +01:00
var slots = new List < ushort > ( ) ;
slots . Add ( slot ) ;
UpdateRecastTimers ( slots ) ;
}
private uint GetHotbarTimer ( uint commandId )
{
ushort slot = FindFirstCommandSlotById ( commandId ) ;
return charaWork . parameterSave . commandSlot_recastTime [ slot - charaWork . commandBorder ] ;
}
public override void Cast ( uint spellId , uint targetId = 0 )
{
if ( aiContainer . CanChangeState ( ) )
aiContainer . Cast ( zone . FindActorInArea < Character > ( targetId = = 0 ? currentTarget : targetId ) , spellId ) ;
2017-09-03 01:01:19 +01:00
else if ( aiContainer . IsCurrentState < MagicState > ( ) )
2017-08-31 05:56:43 +01:00
// You are already casting.
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 32536 , 0x20 ) ;
else
// Please wait a moment and try again.
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 32535 , 0x20 ) ;
}
public override void Ability ( uint abilityId , uint targetId = 0 )
{
if ( aiContainer . CanChangeState ( ) )
aiContainer . Ability ( zone . FindActorInArea < Character > ( targetId = = 0 ? currentTarget : targetId ) , abilityId ) ;
else
// Please wait a moment and try again.
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 32535 , 0x20 ) ;
}
2017-08-24 05:12:30 +01:00
2017-08-31 05:56:43 +01:00
public override void WeaponSkill ( uint skillId , uint targetId = 0 )
2017-08-24 05:12:30 +01:00
{
2017-08-31 05:56:43 +01:00
if ( aiContainer . CanChangeState ( ) )
aiContainer . WeaponSkill ( zone . FindActorInArea < Character > ( targetId = = 0 ? currentTarget : targetId ) , skillId ) ;
else
// Please wait a moment and try again.
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 32535 , 0x20 ) ;
}
2017-08-26 04:08:26 +01:00
2017-08-28 21:45:01 -04:00
public override bool IsValidTarget ( Character target , ValidTarget validTarget )
2017-08-26 04:08:26 +01:00
{
if ( target = = null )
{
// Target does not exist.
2017-08-28 21:45:01 -04:00
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 32511 , 0x20 ) ;
2017-08-26 04:08:26 +01:00
return false ;
}
2017-08-30 00:14:14 +01:00
if ( target . isMovingToSpawn )
{
// That command cannot be performed on the current target.
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 32547 , 0x20 ) ;
return false ;
}
2017-08-26 04:08:26 +01:00
// enemy only
if ( ( validTarget & ValidTarget . Enemy ) ! = 0 )
{
2017-08-31 05:56:43 +01:00
// todo: this seems ambiguous
if ( target . isStatic )
2017-08-26 04:08:26 +01:00
{
// That command cannot be performed on the current target.
2017-08-28 21:45:01 -04:00
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 32547 , 0x20 ) ;
2017-08-26 04:08:26 +01:00
return false ;
}
if ( currentParty ! = null & & target . currentParty = = currentParty )
{
// That command cannot be performed on a party member.
2017-08-28 21:45:01 -04:00
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 32548 , 0x20 ) ;
2017-08-26 04:08:26 +01:00
return false ;
}
// todo: pvp?
2017-08-31 05:56:43 +01:00
if ( target . allegiance = = allegiance )
2017-08-26 04:08:26 +01:00
{
// That command cannot be performed on an ally.
2017-08-28 21:45:01 -04:00
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 32549 , 0x20 ) ;
2017-08-26 04:08:26 +01:00
return false ;
}
2017-09-10 03:41:58 +01:00
bool partyEngaged = false ;
// todo: replace with confrontation status effect? (see how dsp does it)
if ( target . aiContainer . IsEngaged ( ) )
{
if ( currentParty ! = null )
{
if ( target is BattleNpc )
{
var helpingActorId = ( ( BattleNpc ) target ) . GetMobMod ( ( uint ) MobModifier . CallForHelp ) ;
partyEngaged = this . actorId = = helpingActorId | | ( ( ( BattleNpc ) target ) . GetMobMod ( ( uint ) MobModifier . FreeForAll ) ! = 0 ) ;
}
if ( ! partyEngaged )
{
foreach ( var memberId in ( ( Party ) currentParty ) . members )
{
if ( memberId = = target . currentLockedTarget )
{
partyEngaged = true ;
break ;
}
}
}
}
else if ( target . currentLockedTarget = = actorId )
{
partyEngaged = true ;
}
}
else
{
partyEngaged = true ;
}
if ( ! partyEngaged )
{
// That target is already engaged.
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 32520 , 0x20 ) ;
return false ;
}
2017-08-26 04:08:26 +01:00
}
2017-08-31 05:56:43 +01:00
if ( ( validTarget & ValidTarget . Ally ) ! = 0 & & target . allegiance ! = allegiance )
2017-08-26 04:08:26 +01:00
{
// That command cannot be performed on the current target.
2017-08-28 21:45:01 -04:00
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 32547 , 0x20 ) ;
2017-08-26 04:08:26 +01:00
return false ;
}
2017-08-31 05:56:43 +01:00
// todo: isStatic seems ambiguous?
if ( ( validTarget & ValidTarget . NPC ) ! = 0 & & target . isStatic )
2017-08-26 04:08:26 +01:00
return true ;
// todo: why is player always zoning?
// cant target if zoning
if ( target is Player & & ( ( Player ) target ) . playerSession . isUpdatesLocked )
{
// That command cannot be performed on the current target.
2017-08-28 21:45:01 -04:00
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 32547 , 0x20 ) ;
2017-08-26 04:08:26 +01:00
return false ;
}
return true ;
}
2017-08-28 21:45:01 -04:00
public override bool CanCast ( Character target , BattleCommand spell )
2017-08-26 04:08:26 +01:00
{
2019-01-29 00:02:09 -05:00
//Might want to do these with a CommandResult instead to be consistent with the rest of command stuff
2017-08-31 05:56:43 +01:00
if ( GetHotbarTimer ( spell . id ) > Utils . UnixTimeStampUTC ( ) )
{
// todo: this needs confirming
// Please wait a moment and try again.
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 32535 , 0x20 , ( uint ) spell . id ) ;
return false ;
}
2017-08-26 04:08:26 +01:00
if ( target = = null )
{
// Target does not exist.
2017-08-28 21:45:01 -04:00
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 32511 , 0x20 , ( uint ) spell . id ) ;
2017-08-26 04:08:26 +01:00
return false ;
}
2018-07-02 00:45:06 -05:00
if ( Utils . XZDistance ( positionX , positionZ , target . positionX , target . positionZ ) > spell . range )
2017-08-26 04:08:26 +01:00
{
2018-07-02 00:45:06 -05:00
// The target is too far away.
2017-08-30 00:14:14 +01:00
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 32539 , 0x20 , ( uint ) spell . id ) ;
2017-08-26 04:08:26 +01:00
return false ;
}
2018-07-02 00:45:06 -05:00
if ( Utils . XZDistance ( positionX , positionZ , target . positionX , target . positionZ ) < spell . minRange )
{
// The target is too close.
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 32538 , 0x20 , ( uint ) spell . id ) ;
return false ;
}
if ( target . positionY - positionY > ( spell . rangeHeight / 2 ) )
{
// The target is too far above you.
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 32540 , 0x20 , ( uint ) spell . id ) ;
return false ;
}
if ( positionY - target . positionY > ( spell . rangeHeight / 2 ) )
{
// The target is too far below you.
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 32541 , 0x20 , ( uint ) spell . id ) ;
return false ;
}
2018-02-15 13:20:46 -06:00
if ( ! IsValidTarget ( target , spell . mainTarget ) | | ! spell . IsValidMainTarget ( this , target ) )
2017-08-26 04:08:26 +01:00
{
// error packet is set in IsValidTarget
return false ;
}
return true ;
}
2017-08-28 21:45:01 -04:00
public override bool CanWeaponSkill ( Character target , BattleCommand skill )
2017-08-26 04:08:26 +01:00
{
// todo: see worldmaster ids 32558~32557 for proper ko message and stuff
2017-08-31 05:56:43 +01:00
if ( GetHotbarTimer ( skill . id ) > Utils . UnixTimeStampUTC ( ) )
{
// todo: this needs confirming
// Please wait a moment and try again.
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 32535 , 0x20 , ( uint ) skill . id ) ;
return false ;
}
2018-02-15 13:20:46 -06:00
2017-08-26 04:08:26 +01:00
if ( target = = null )
{
// Target does not exist.
2017-08-28 21:45:01 -04:00
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 32511 , 0x20 , ( uint ) skill . id ) ;
2017-08-26 04:08:26 +01:00
return false ;
}
2018-02-15 13:20:46 -06:00
2018-07-02 00:45:06 -05:00
//Original game checked height difference before horizontal distance
if ( target . positionY - positionY > ( skill . rangeHeight / 2 ) )
{
// The target is too far above you.
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 32540 , 0x20 , ( uint ) skill . id ) ;
return false ;
}
if ( positionY - target . positionY > ( skill . rangeHeight / 2 ) )
{
// The target is too far below you.
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 32541 , 0x20 , ( uint ) skill . id ) ;
return false ;
}
var targetDist = Utils . XZDistance ( positionX , positionZ , target . positionX , target . positionZ ) ;
if ( targetDist > skill . range )
2017-08-26 04:08:26 +01:00
{
// The target is out of range.
2018-07-02 00:45:06 -05:00
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 32537 , 0x20 , ( uint ) skill . id ) ;
return false ;
}
if ( targetDist < skill . minRange )
{
// The target is too close.
SendGameMessage ( Server . GetWorldManager ( ) . GetActor ( ) , 32538 , 0x20 , ( uint ) skill . id ) ;
2017-08-26 04:08:26 +01:00
return false ;
}
2018-02-15 13:20:46 -06:00
2018-07-02 00:45:06 -05:00
2018-02-15 13:20:46 -06:00
if ( ! IsValidTarget ( target , skill . validTarget ) | | ! skill . IsValidMainTarget ( this , target ) )
2017-08-26 04:08:26 +01:00
{
// error packet is set in IsValidTarget
return false ;
}
2018-02-15 13:20:46 -06:00
2017-08-26 04:08:26 +01:00
return true ;
}
2017-08-28 04:45:20 +01:00
2019-01-29 00:02:09 -05:00
public override void OnAttack ( State state , CommandResult action , ref CommandResult error )
2017-08-28 04:45:20 +01:00
{
2018-02-15 13:20:46 -06:00
var target = state . GetTarget ( ) ;
2017-08-28 21:45:01 -04:00
base . OnAttack ( state , action , ref error ) ;
2018-02-15 13:20:46 -06:00
2017-08-31 05:56:43 +01:00
// todo: switch based on main weap (also probably move this anim assignment somewhere else)
action . animation = 0x19001000 ;
2017-08-28 21:45:01 -04:00
if ( error = = null )
2017-08-29 01:15:12 +01:00
{
// melee attack animation
2017-08-28 21:45:01 -04:00
//action.animation = 0x19001000;
2017-08-29 01:15:12 +01:00
}
2017-09-03 01:01:19 +01:00
if ( target is BattleNpc )
2017-08-29 01:15:12 +01:00
{
2018-02-15 13:20:46 -06:00
( ( BattleNpc ) target ) . hateContainer . UpdateHate ( this , action . enmity ) ;
2017-08-29 01:15:12 +01:00
}
2017-10-10 13:32:47 -05:00
LuaEngine . GetInstance ( ) . OnSignal ( "playerAttack" ) ;
2017-08-28 04:45:20 +01:00
}
2017-08-31 05:56:43 +01:00
2019-01-29 00:02:09 -05:00
public override void OnCast ( State state , CommandResult [ ] actions , BattleCommand spell , ref CommandResult [ ] errors )
2017-08-31 05:56:43 +01:00
{
// todo: update hotbar timers to skill's recast time (also needs to be done on class change or equip crap)
2018-02-15 13:20:46 -06:00
base . OnCast ( state , actions , spell , ref errors ) ;
2017-12-08 00:58:39 -06:00
// todo: should just make a thing that updates the one slot cause this is dumb as hell
2018-02-15 13:20:46 -06:00
UpdateHotbarTimer ( spell . id , spell . recastTimeMs ) ;
//LuaEngine.GetInstance().OnSignal("spellUse");
2017-08-31 05:56:43 +01:00
}
2019-01-29 00:02:09 -05:00
public override void OnWeaponSkill ( State state , CommandResult [ ] actions , BattleCommand skill , ref CommandResult [ ] errors )
2017-08-31 05:56:43 +01:00
{
// todo: update hotbar timers to skill's recast time (also needs to be done on class change or equip crap)
2018-02-15 13:20:46 -06:00
base . OnWeaponSkill ( state , actions , skill , ref errors ) ;
2017-08-31 05:56:43 +01:00
// todo: should just make a thing that updates the one slot cause this is dumb as hell
2018-02-15 13:20:46 -06:00
UpdateHotbarTimer ( skill . id , skill . recastTimeMs ) ;
2017-09-03 01:01:19 +01:00
// todo: this really shouldnt be called on each ws?
lua . LuaEngine . CallLuaBattleFunction ( this , "onWeaponSkill" , this , state . GetTarget ( ) , skill ) ;
2017-10-11 19:23:40 +01:00
LuaEngine . GetInstance ( ) . OnSignal ( "weaponskillUse" ) ;
2017-08-31 05:56:43 +01:00
}
2017-10-11 19:23:40 +01:00
2019-01-29 00:02:09 -05:00
public override void OnAbility ( State state , CommandResult [ ] actions , BattleCommand ability , ref CommandResult [ ] errors )
2017-10-11 19:23:40 +01:00
{
2018-02-15 13:20:46 -06:00
base . OnAbility ( state , actions , ability , ref errors ) ;
UpdateHotbarTimer ( ability . id , ability . recastTimeMs ) ;
2017-10-11 19:23:40 +01:00
LuaEngine . GetInstance ( ) . OnSignal ( "abilityUse" ) ;
}
2017-09-27 18:10:22 -05:00
//Handles exp being added, does not handle figuring out exp bonus from buffs or skill/link chains or any of that
2019-01-29 00:02:09 -05:00
//Returns CommandResults that can be sent to display the EXP gained number and level ups
2018-05-28 16:28:44 -05:00
//exp should be a ushort single the exp graphic overflows after ~65k
2019-01-29 00:02:09 -05:00
public List < CommandResult > AddExp ( int exp , byte classId , byte bonusPercent = 0 )
2018-04-18 16:06:41 -05:00
{
2019-01-29 00:02:09 -05:00
List < CommandResult > actionList = new List < CommandResult > ( ) ;
2017-09-27 18:10:22 -05:00
exp + = ( int ) Math . Ceiling ( ( exp * bonusPercent / 100.0f ) ) ;
2018-04-18 16:06:41 -05:00
2018-05-28 16:28:44 -05:00
//You earn [exp] (+[bonusPercent]%) experience points.
//In non-english languages there are unique messages for each language, hence the use of ClassExperienceTextIds
2019-01-29 00:02:09 -05:00
actionList . Add ( new CommandResult ( actorId , BattleUtils . ClassExperienceTextIds [ classId ] , 0 , ( ushort ) exp , bonusPercent ) ) ;
2018-04-18 16:06:41 -05:00
2017-09-27 18:10:22 -05:00
bool leveled = false ;
int diff = MAXEXP [ GetLevel ( ) - 1 ] - charaWork . battleSave . skillPoint [ classId - 1 ] ;
2017-09-30 07:28:08 -05:00
//While there is enough experience to level up, keep leveling up, unlocking skills and removing experience from exp until we don't have enough to level up
2017-09-27 18:10:22 -05:00
while ( exp > = diff & & GetLevel ( ) < charaWork . battleSave . skillLevelCap [ classId ] )
{
//Level up
LevelUp ( classId ) ;
leveled = true ;
//Reduce exp based on how much exp is needed to level
exp - = diff ;
diff = MAXEXP [ GetLevel ( ) - 1 ] ;
}
if ( leveled )
{
//Set exp to current class to 0 so that exp is added correctly
charaWork . battleSave . skillPoint [ classId - 1 ] = 0 ;
//send new level
ActorPropertyPacketUtil expPropertyPacket2 = new ActorPropertyPacketUtil ( "charaWork/exp" , this ) ;
ActorPropertyPacketUtil expPropertyPacket3 = new ActorPropertyPacketUtil ( "charaWork/stateForAll" , this ) ;
2018-10-08 15:11:43 -04:00
expPropertyPacket2 . AddProperty ( String . Format ( "charaWork.battleSave.skillLevel[{0}]" , classId - 1 ) ) ;
expPropertyPacket2 . AddProperty ( "charaWork.parameterSave.state_mainSkillLevel" ) ;
2017-09-27 18:10:22 -05:00
QueuePackets ( expPropertyPacket2 . Done ( ) ) ;
QueuePackets ( expPropertyPacket3 . Done ( ) ) ;
//play levelup animation (do this outside LevelUp so that it only plays once if multiple levels are earned
//also i dunno how to do this
2017-09-30 07:28:08 -05:00
Database . SetLevel ( this , classId , GetLevel ( ) ) ;
2017-10-06 20:45:10 -05:00
Database . SavePlayerCurrentClass ( this ) ;
2017-09-27 18:10:22 -05:00
}
2017-09-30 07:28:08 -05:00
//Cap experience for level 50
2017-09-27 18:10:22 -05:00
charaWork . battleSave . skillPoint [ classId - 1 ] = Math . Min ( charaWork . battleSave . skillPoint [ classId - 1 ] + exp , MAXEXP [ GetLevel ( ) - 1 ] ) ;
ActorPropertyPacketUtil expPropertyPacket = new ActorPropertyPacketUtil ( "charaWork/battleStateForSelf" , this ) ;
2018-10-08 15:11:43 -04:00
expPropertyPacket . AddProperty ( String . Format ( "charaWork.battleSave.skillPoint[{0}]" , classId - 1 ) ) ;
2017-09-27 18:10:22 -05:00
2017-09-30 07:28:08 -05:00
QueuePackets ( expPropertyPacket . Done ( ) ) ;
Database . SetExp ( this , classId , charaWork . battleSave . skillPoint [ classId - 1 ] ) ;
2018-04-18 16:06:41 -05:00
return actionList ;
2017-09-27 18:10:22 -05:00
}
2018-04-18 16:06:41 -05:00
//Increaess level of current class and equips new abilities earned at that level
2019-01-29 00:02:09 -05:00
public void LevelUp ( byte classId , List < CommandResult > actionList = null )
2017-09-27 18:10:22 -05:00
{
if ( charaWork . battleSave . skillLevel [ classId - 1 ] < charaWork . battleSave . skillLevelCap [ classId ] )
{
//Increase level
charaWork . battleSave . skillLevel [ classId - 1 ] + + ;
charaWork . parameterSave . state_mainSkillLevel + + ;
2018-04-18 16:06:41 -05:00
//33909: You gain level [level]
2018-10-08 15:11:43 -04:00
if ( actionList ! = null )
2019-01-29 00:02:09 -05:00
actionList . Add ( new CommandResult ( actorId , 33909 , 0 , ( ushort ) charaWork . battleSave . skillLevel [ classId - 1 ] ) ) ;
2018-04-18 16:06:41 -05:00
//If there's any abilites that unlocks at this level, equip them.
2017-09-30 07:28:08 -05:00
List < uint > commandIds = Server . GetWorldManager ( ) . GetBattleCommandIdByLevel ( classId , GetLevel ( ) ) ;
foreach ( uint commandId in commandIds )
2017-09-27 18:10:22 -05:00
{
EquipAbilityInFirstOpenSlot ( classId , commandId , false ) ;
byte jobId = ConvertClassIdToJobId ( classId ) ;
2017-09-30 07:28:08 -05:00
if ( jobId ! = classId )
2017-09-27 18:10:22 -05:00
EquipAbilityInFirstOpenSlot ( jobId , commandId , false ) ;
2018-04-18 16:06:41 -05:00
//33926: You learn [command].
2018-10-08 15:11:43 -04:00
if ( actionList ! = null )
{
if ( classId = = GetCurrentClassOrJob ( ) | | jobId = = GetCurrentClassOrJob ( ) )
2019-01-29 00:02:09 -05:00
actionList . Add ( new CommandResult ( actorId , 33926 , commandId ) ) ;
2018-10-08 15:11:43 -04:00
}
2017-09-27 18:10:22 -05:00
}
}
}
public static byte ConvertClassIdToJobId ( byte classId )
{
byte jobId = classId ;
switch ( classId )
{
case CLASSID_PUG :
case CLASSID_GLA :
case CLASSID_MRD :
jobId + = 13 ;
break ;
case CLASSID_ARC :
case CLASSID_LNC :
2017-09-30 07:28:08 -05:00
jobId + = 11 ;
2017-09-27 18:10:22 -05:00
break ;
case CLASSID_THM :
case CLASSID_CNJ :
jobId + = 4 ;
break ;
}
return jobId ;
}
2017-09-30 07:28:08 -05:00
public void SetCurrentJob ( byte jobId )
{
currentJob = jobId ;
BroadcastPacket ( SetCurrentJobPacket . BuildPacket ( actorId , jobId ) , true ) ;
Database . LoadHotbar ( this ) ;
2018-02-15 13:20:46 -06:00
SendCharaExpInfo ( ) ;
2017-09-30 07:28:08 -05:00
}
2017-12-08 00:58:39 -06:00
//Gets the id of the player's current job. If they aren't a job, gets the id of their class
2017-09-30 07:28:08 -05:00
public byte GetCurrentClassOrJob ( )
{
if ( currentJob ! = 0 )
return ( byte ) currentJob ;
return charaWork . parameterSave . state_mainSkill [ 0 ] ;
}
2017-10-10 13:32:47 -05:00
public void hpstuff ( uint hp )
{
SetMaxHP ( hp ) ;
2017-12-08 00:58:39 -06:00
SetHP ( hp ) ;
2017-10-10 13:32:47 -05:00
mpMaxBase = ( ushort ) hp ;
charaWork . parameterSave . mpMax = ( short ) hp ;
charaWork . parameterSave . mp = ( short ) hp ;
2017-12-08 00:58:39 -06:00
AddTP ( 3000 ) ;
updateFlags | = ActorUpdateFlags . HpTpMp ;
2017-10-10 13:32:47 -05:00
}
2018-02-15 13:20:46 -06:00
public void SetCombos ( int comboId1 = 0 , int comboId2 = 0 )
{
SetCombos ( new int [ ] { comboId1 , comboId2 } ) ;
}
public void SetCombos ( int [ ] comboIds )
{
Array . Copy ( comboIds , playerWork . comboNextCommandId , 2 ) ;
//If we're starting or continuing a combo chain, add the status effect and combo cost bonus
if ( comboIds [ 0 ] ! = 0 )
{
2018-07-02 00:45:06 -05:00
StatusEffect comboEffect = new StatusEffect ( this , Server . GetWorldManager ( ) . GetStatusEffect ( ( uint ) StatusEffectId . Combo ) ) ;
comboEffect . SetDuration ( 13 ) ;
2018-02-15 13:20:46 -06:00
comboEffect . SetOverwritable ( 1 ) ;
statusEffects . AddStatusEffect ( comboEffect , this , true ) ;
playerWork . comboCostBonusRate = 1 ;
}
//Otherwise we're ending a combo, remove the status
else
{
statusEffects . RemoveStatusEffect ( statusEffects . GetStatusEffectById ( ( uint ) StatusEffectId . Combo ) ) ;
playerWork . comboCostBonusRate = 0 ;
}
ActorPropertyPacketUtil comboPropertyPacket = new ActorPropertyPacketUtil ( "playerWork/combo" , this ) ;
2018-10-08 15:11:43 -04:00
comboPropertyPacket . AddProperty ( "playerWork.comboCostBonusRate" ) ;
comboPropertyPacket . AddProperty ( "playerWork.comboNextCommandId[0]" ) ;
comboPropertyPacket . AddProperty ( "playerWork.comboNextCommandId[1]" ) ;
2018-02-15 13:20:46 -06:00
QueuePackets ( comboPropertyPacket . Done ( ) ) ;
}
public override void CalculateBaseStats ( )
{
base . CalculateBaseStats ( ) ;
//Add weapon property mod
var equip = GetEquipment ( ) ;
2019-06-02 16:57:46 -04:00
var mainHandItem = equip . GetItemAtSlot ( SLOT_MAINHAND ) ;
2018-02-15 13:20:46 -06:00
var damageAttribute = 0 ;
var attackDelay = 3000 ;
2018-05-27 14:51:39 -05:00
var hitCount = 1 ;
2018-02-15 13:20:46 -06:00
if ( mainHandItem ! = null )
{
var mainHandWeapon = ( Server . GetItemGamedata ( mainHandItem . itemId ) as WeaponItem ) ;
damageAttribute = mainHandWeapon . damageAttributeType1 ;
attackDelay = ( int ) ( mainHandWeapon . damageInterval * 1000 ) ;
hitCount = mainHandWeapon . frequency ;
}
2019-06-02 16:57:46 -04:00
var hasShield = equip . GetItemAtSlot ( SLOT_OFFHAND ) ! = null ? 1 : 0 ;
2018-02-15 13:20:46 -06:00
SetMod ( ( uint ) Modifier . HasShield , hasShield ) ;
SetMod ( ( uint ) Modifier . AttackType , damageAttribute ) ;
SetMod ( ( uint ) Modifier . AttackDelay , attackDelay ) ;
SetMod ( ( uint ) Modifier . HitCount , hitCount ) ;
2018-04-18 16:06:41 -05:00
//These stats all correlate in a 3:2 fashion
//It seems these stats don't actually increase their respective stats. The magic stats do, however
AddMod ( ( uint ) Modifier . Attack , ( long ) ( GetMod ( Modifier . Strength ) * 0.667 ) ) ;
AddMod ( ( uint ) Modifier . Accuracy , ( long ) ( GetMod ( Modifier . Dexterity ) * 0.667 ) ) ;
AddMod ( ( uint ) Modifier . Defense , ( long ) ( GetMod ( Modifier . Vitality ) * 0.667 ) ) ;
//These stats correlate in a 4:1 fashion. (Unsure if MND is accurate but it would make sense for it to be)
AddMod ( ( uint ) Modifier . MagicAttack , ( long ) ( ( float ) GetMod ( Modifier . Intelligence ) * 0.25 ) ) ;
AddMod ( ( uint ) Modifier . MagicAccuracy , ( long ) ( ( float ) GetMod ( Modifier . Mind ) * 0.25 ) ) ;
AddMod ( ( uint ) Modifier . MagicHeal , ( long ) ( ( float ) GetMod ( Modifier . Mind ) * 0.25 ) ) ;
AddMod ( ( uint ) Modifier . MagicEvasion , ( long ) ( ( float ) GetMod ( Modifier . Piety ) * 0.25 ) ) ;
AddMod ( ( uint ) Modifier . MagicEnfeeblingPotency , ( long ) ( ( float ) GetMod ( Modifier . Piety ) * 0.25 ) ) ;
//VIT correlates to HP in a 1:1 fashion
AddMod ( ( uint ) Modifier . Hp , ( long ) ( ( float ) Modifier . Vitality ) ) ;
CalculateTraitMods ( ) ;
2018-02-15 13:20:46 -06:00
}
2018-04-18 16:06:41 -05:00
public bool HasTrait ( ushort id )
2018-02-15 13:20:46 -06:00
{
2018-04-18 16:06:41 -05:00
BattleTrait trait = Server . GetWorldManager ( ) . GetBattleTrait ( id ) ;
return HasTrait ( trait ) ;
}
public bool HasTrait ( BattleTrait trait )
{
return ( trait ! = null ) & & ( trait . job = = GetClass ( ) ) & & ( trait . level < = GetLevel ( ) ) ;
}
public void CalculateTraitMods ( )
{
var traitIds = Server . GetWorldManager ( ) . GetAllBattleTraitIdsForClass ( ( byte ) GetClass ( ) ) ;
foreach ( var traitId in traitIds )
{
var trait = Server . GetWorldManager ( ) . GetBattleTrait ( traitId ) ;
if ( HasTrait ( trait ) )
{
AddMod ( trait . modifier , trait . bonus ) ;
}
}
2018-02-15 13:20:46 -06:00
}
2018-07-02 00:45:06 -05:00
public bool HasItemEquippedInSlot ( uint itemId , ushort slot )
{
var equippedItem = equipment . GetItemAtSlot ( slot ) ;
return equippedItem ! = null & & equippedItem . itemId = = itemId ;
}
2017-09-05 12:37:23 -04:00
2017-12-17 15:25:42 -05:00
public Retainer GetSpawnedRetainer ( )
{
return currentSpawnedRetainer ;
}
2017-10-01 12:23:54 -04:00
public void StartTradeTransaction ( Player otherPlayer )
{
2019-06-02 16:57:46 -04:00
myOfferings = new ReferencedItemPackage ( this , ItemPackage . MAXSIZE_TRADE , ItemPackage . TRADE ) ;
2017-10-08 12:26:22 -04:00
otherTrader = otherPlayer ;
isTradeAccepted = false ;
}
2017-10-01 12:23:54 -04:00
2017-10-08 12:26:22 -04:00
public Player GetOtherTrader ( )
{
return otherTrader ;
}
2019-06-02 16:57:46 -04:00
public ReferencedItemPackage GetTradeOfferings ( )
2017-10-08 12:26:22 -04:00
{
return myOfferings ;
}
2017-10-01 12:23:54 -04:00
2017-10-08 12:26:22 -04:00
public bool IsTrading ( )
{
return otherTrader ! = null ;
}
2017-10-01 12:23:54 -04:00
2017-10-08 12:26:22 -04:00
public bool IsTradeAccepted ( )
{
return isTradeAccepted ;
2017-10-01 12:23:54 -04:00
}
2019-06-02 16:57:46 -04:00
public void AddTradeItem ( ushort slot , ItemRefParam chosenItem , int tradeQuantity )
2017-10-01 12:23:54 -04:00
{
2017-10-08 12:26:22 -04:00
if ( ! IsTrading ( ) )
return ;
2019-06-02 16:57:46 -04:00
//Get chosen item
InventoryItem offeredItem = itemPackages [ chosenItem . itemPackage ] . GetItemAtSlot ( chosenItem . slot ) ;
offeredItem . SetTradeQuantity ( tradeQuantity ) ;
myOfferings . Set ( slot , offeredItem ) ;
SendTradePackets ( ) ;
2017-10-01 12:23:54 -04:00
}
2019-06-02 16:57:46 -04:00
public void RemoveTradeItem ( ushort slot )
2017-10-01 12:23:54 -04:00
{
2017-10-08 12:26:22 -04:00
if ( ! IsTrading ( ) )
return ;
2019-06-02 16:57:46 -04:00
InventoryItem offeredItem = myOfferings . GetItemAtSlot ( slot ) ;
offeredItem . SetNormal ( ) ;
myOfferings . Clear ( slot ) ;
SendTradePackets ( ) ;
2017-10-08 12:26:22 -04:00
}
2017-10-01 12:23:54 -04:00
2019-06-02 16:57:46 -04:00
public void ClearTradeItems ( )
2017-10-08 12:26:22 -04:00
{
if ( ! IsTrading ( ) )
2019-06-02 16:57:46 -04:00
return ;
2017-10-01 12:23:54 -04:00
2019-06-02 16:57:46 -04:00
for ( ushort i = 0 ; i < myOfferings . GetCapacity ( ) ; i + + )
{
InventoryItem offeredItem = myOfferings . GetItemAtSlot ( i ) ;
if ( offeredItem ! = null )
offeredItem . SetNormal ( ) ;
}
myOfferings . ClearAll ( ) ;
SendTradePackets ( ) ;
2017-10-01 12:23:54 -04:00
}
2019-06-02 16:57:46 -04:00
private void SendTradePackets ( )
2017-10-08 12:26:22 -04:00
{
2019-06-02 16:57:46 -04:00
//Send to self
QueuePacket ( InventoryBeginChangePacket . BuildPacket ( actorId , true ) ) ;
myOfferings . SendUpdate ( this ) ;
QueuePacket ( InventoryEndChangePacket . BuildPacket ( actorId ) ) ;
2017-10-01 12:23:54 -04:00
2019-06-02 16:57:46 -04:00
//Send to other trader
otherTrader . QueuePacket ( InventoryBeginChangePacket . BuildPacket ( actorId , true ) ) ;
myOfferings . SendUpdateAsItemPackage ( otherTrader ) ;
otherTrader . QueuePacket ( InventoryEndChangePacket . BuildPacket ( actorId ) ) ;
2017-10-08 12:26:22 -04:00
}
public void AcceptTrade ( bool accepted )
2017-10-01 12:23:54 -04:00
{
2017-10-08 12:26:22 -04:00
if ( ! IsTrading ( ) )
return ;
isTradeAccepted = accepted ;
2017-10-01 12:23:54 -04:00
}
public void FinishTradeTransaction ( )
{
2019-06-02 16:57:46 -04:00
if ( myOfferings ! = null )
{
myOfferings . ClearAll ( ) ;
for ( ushort i = 0 ; i < myOfferings . GetCapacity ( ) ; i + + )
{
InventoryItem offeredItem = myOfferings . GetItemAtSlot ( i ) ;
if ( offeredItem ! = null )
offeredItem . SetNormal ( ) ;
}
QueuePacket ( InventoryBeginChangePacket . BuildPacket ( actorId , true ) ) ;
myOfferings . SendUpdate ( this ) ;
QueuePacket ( InventoryEndChangePacket . BuildPacket ( actorId ) ) ;
}
2017-10-08 12:26:22 -04:00
isTradeAccepted = false ;
2017-10-01 12:23:54 -04:00
myOfferings = null ;
otherTrader = null ;
}
2019-06-02 16:57:46 -04:00
2017-03-07 00:09:37 -05:00
}
}