2012-01-29 14:28:19 -05:00
# include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
2011-10-03 14:41:19 -04:00
# include "cPlayer.h"
# include "cServer.h"
2011-12-31 23:55:17 -05:00
# include "cCreativeInventory.h"
# include "cSurvivalInventory.h"
2011-10-03 14:41:19 -04:00
# include "cClientHandle.h"
# include "cWorld.h"
# include "cPickup.h"
# include "cPluginManager.h"
# include "cChunk.h"
# include "cWindow.h"
# include "cBlockEntity.h"
# include "cGroupManager.h"
# include "cGroup.h"
# include "cChatColor.h"
# include "cItem.h"
# include "cTracer.h"
# include "cRoot.h"
2011-11-01 17:57:08 -04:00
# include "cMakeDir.h"
2011-12-25 23:06:29 -05:00
# include "cTimer.h"
2011-12-26 04:09:47 -05:00
# include "MersenneTwister.h"
2011-10-03 14:41:19 -04:00
# include "packets/cPacket_NamedEntitySpawn.h"
# include "packets/cPacket_EntityLook.h"
# include "packets/cPacket_TeleportEntity.h"
# include "packets/cPacket_RelativeEntityMove.h"
# include "packets/cPacket_RelativeEntityMoveLook.h"
# include "packets/cPacket_UpdateHealth.h"
# include "packets/cPacket_Respawn.h"
# include "packets/cPacket_PlayerPosition.h"
# include "packets/cPacket_DestroyEntity.h"
# include "packets/cPacket_Metadata.h"
# include "packets/cPacket_Chat.h"
2011-11-10 13:28:21 -05:00
# include "packets/cPacket_NewInvalidState.h"
2011-12-25 20:07:35 -05:00
# include "packets/cPacket_PlayerListItem.h"
2011-12-29 08:16:23 -05:00
# include "packets/cPacket_BlockAction.h"
2011-10-03 14:41:19 -04:00
# include "Vector3d.h"
# include "Vector3f.h"
# include "../iniFile/iniFile.h"
2011-10-31 17:30:14 -04:00
# include <json/json.h>
2011-10-03 14:41:19 -04:00
2011-11-06 04:23:20 -05:00
# define float2int(x) ((x)<0 ? ((int)(x))-1 : (int)(x))
2012-02-01 04:12:54 -05:00
2011-10-03 14:41:19 -04:00
CLASS_DEFINITION ( cPlayer , cPawn ) ;
typedef std : : map < std : : string , bool > PermissionMap ;
struct cPlayer : : sPlayerState
{
PermissionMap ResolvedPermissions ;
PermissionMap Permissions ;
cPlayer : : GroupList ResolvedGroups ;
cPlayer : : GroupList Groups ;
std : : string PlayerName ;
2011-11-02 16:19:57 -04:00
std : : string LoadedWorldName ;
2011-10-03 14:41:19 -04:00
} ;
2012-02-01 17:38:03 -05:00
cPlayer : : cPlayer ( cClientHandle * a_Client , const AString & a_PlayerName )
2011-12-27 21:10:05 -05:00
: m_GameMode ( 0 )
2011-11-09 17:17:30 -05:00
, m_IP ( " " )
2011-11-01 16:09:13 -04:00
, m_LastBlockActionTime ( 0 )
2011-11-10 11:30:14 -05:00
, m_LastBlockActionCnt ( 0 )
2011-10-03 14:41:19 -04:00
, m_bVisible ( true )
, m_LastGroundHeight ( 0 )
, m_bTouchGround ( false )
, m_Stance ( 0.0 )
, m_Inventory ( 0 )
, m_CurrentWindow ( 0 )
, m_TimeLastPickupCheck ( 0.f )
, m_Color ( ' - ' )
, m_ClientHandle ( a_Client )
, m_pState ( new sPlayerState )
{
m_EntityType = E_PLAYER ;
2011-12-27 21:10:05 -05:00
SetMaxHealth ( 20 ) ;
2011-12-29 10:31:48 -05:00
SetMaxFoodLevel ( 125 ) ;
2011-12-31 23:55:17 -05:00
m_Inventory = new cSurvivalInventory ( this ) ;
m_CreativeInventory = new cCreativeInventory ( this ) ;
2011-12-25 23:06:29 -05:00
cTimer t1 ;
m_LastPlayerListTime = t1 . GetNowTime ( ) ;
2011-10-03 14:41:19 -04:00
m_TimeLastTeleportPacket = cWorld : : GetTime ( ) ;
m_TimeLastPickupCheck = cWorld : : GetTime ( ) ;
2011-11-06 04:23:20 -05:00
2011-10-03 14:41:19 -04:00
m_pState - > PlayerName = a_PlayerName ;
m_bDirtyPosition = true ; // So chunks are streamed to player at spawn
if ( ! LoadFromDisk ( ) )
{
m_Inventory - > Clear ( ) ;
2012-01-01 13:45:28 -05:00
m_CreativeInventory - > Clear ( ) ;
2012-02-15 17:50:00 -05:00
m_Pos . x = cRoot : : Get ( ) - > GetDefaultWorld ( ) - > GetSpawnX ( ) ;
m_Pos . y = cRoot : : Get ( ) - > GetDefaultWorld ( ) - > GetSpawnY ( ) ;
m_Pos . z = cRoot : : Get ( ) - > GetDefaultWorld ( ) - > GetSpawnZ ( ) ;
2011-10-03 14:41:19 -04:00
}
2011-11-01 17:57:08 -04:00
}
2011-10-03 14:41:19 -04:00
2011-11-01 17:57:08 -04:00
void cPlayer : : Initialize ( cWorld * a_World )
{
cPawn : : Initialize ( a_World ) ;
GetWorld ( ) - > AddPlayer ( this ) ;
2011-10-03 14:41:19 -04:00
}
cPlayer : : ~ cPlayer ( void )
{
SaveToDisk ( ) ;
m_ClientHandle = 0 ;
2011-11-06 04:23:20 -05:00
2011-12-25 09:03:01 -05:00
CloseWindow ( - 1 ) ;
2011-10-03 14:41:19 -04:00
if ( m_Inventory )
{
delete m_Inventory ;
m_Inventory = 0 ;
}
2011-12-31 23:55:17 -05:00
if ( m_CreativeInventory )
{
delete m_CreativeInventory ;
}
2011-10-03 14:41:19 -04:00
delete m_pState ;
2012-02-13 16:47:03 -05:00
m_World - > RemovePlayer ( this ) ;
2011-10-03 14:41:19 -04:00
}
2011-11-01 16:09:13 -04:00
2012-02-13 16:47:03 -05:00
cPacket * cPlayer : : GetSpawnPacket ( void ) const
2011-10-03 14:41:19 -04:00
{
2012-02-13 16:47:03 -05:00
if ( ! m_bVisible )
2011-10-03 14:41:19 -04:00
{
2012-02-13 16:47:03 -05:00
return NULL ;
2011-10-03 14:41:19 -04:00
}
2012-02-13 16:47:03 -05:00
cPacket_NamedEntitySpawn * SpawnPacket = new cPacket_NamedEntitySpawn ;
SpawnPacket - > m_UniqueID = m_UniqueID ;
SpawnPacket - > m_PlayerName = m_pState - > PlayerName ;
2012-02-15 17:50:00 -05:00
SpawnPacket - > m_PosX = ( int ) ( m_Pos . x * 32 ) ;
SpawnPacket - > m_PosY = ( int ) ( m_Pos . y * 32 ) ;
SpawnPacket - > m_PosZ = ( int ) ( m_Pos . z * 32 ) ;
SpawnPacket - > m_Rotation = ( char ) ( ( m_Rot . x / 360.f ) * 256 ) ;
SpawnPacket - > m_Pitch = ( char ) ( ( m_Rot . y / 360.f ) * 256 ) ;
2012-02-13 16:47:03 -05:00
SpawnPacket - > m_CurrentItem = ( short ) m_Inventory - > GetEquippedItem ( ) . m_ItemID ;
return SpawnPacket ;
2011-10-03 14:41:19 -04:00
}
2012-02-13 16:47:03 -05:00
2011-10-03 14:41:19 -04:00
void cPlayer : : Tick ( float a_Dt )
{
2012-02-13 16:47:03 -05:00
cChunkPtr InChunk = GetWorld ( ) - > GetChunk ( m_ChunkX , m_ChunkY , m_ChunkZ ) ;
2011-12-24 18:34:30 -05:00
2011-12-27 21:10:05 -05:00
cPawn : : Tick ( a_Dt ) ;
2012-02-02 16:13:24 -05:00
if ( m_bDirtyOrientation & & ! m_bDirtyPosition )
2011-10-03 14:41:19 -04:00
{
cPacket_EntityLook EntityLook ( this ) ;
InChunk - > Broadcast ( EntityLook , m_ClientHandle ) ;
m_bDirtyOrientation = false ;
2012-02-02 16:13:24 -05:00
}
2012-02-13 16:47:03 -05:00
else if ( m_bDirtyPosition )
2011-10-03 14:41:19 -04:00
{
cRoot : : Get ( ) - > GetPluginManager ( ) - > CallHook ( cPluginManager : : E_PLUGIN_PLAYER_MOVE , 1 , this ) ;
float DiffX = ( float ) ( GetPosX ( ) - m_LastPosX ) ;
float DiffY = ( float ) ( GetPosY ( ) - m_LastPosY ) ;
float DiffZ = ( float ) ( GetPosZ ( ) - m_LastPosZ ) ;
2012-02-13 16:47:03 -05:00
float SqrDist = DiffX * DiffX + DiffY * DiffY + DiffZ * DiffZ ;
if (
( SqrDist > 4 * 4 ) | | // 4 blocks is max Relative Move
( cWorld : : GetTime ( ) - m_TimeLastTeleportPacket > 2 ) // Send an absolute position every 2 seconds
)
2011-10-03 14:41:19 -04:00
{
//LOG("Teleported %f", sqrtf(SqrDist) );
cPacket_TeleportEntity TeleportEntity ( this ) ;
InChunk - > Broadcast ( TeleportEntity , m_ClientHandle ) ;
m_TimeLastTeleportPacket = cWorld : : GetTime ( ) ;
}
else
{ // Relative move sucks balls! It's always wrong wtf!
if ( m_bDirtyOrientation )
{
cPacket_RelativeEntityMoveLook RelativeEntityMoveLook ;
RelativeEntityMoveLook . m_UniqueID = GetUniqueID ( ) ;
RelativeEntityMoveLook . m_MoveX = ( char ) ( DiffX * 32 ) ;
RelativeEntityMoveLook . m_MoveY = ( char ) ( DiffY * 32 ) ;
RelativeEntityMoveLook . m_MoveZ = ( char ) ( DiffZ * 32 ) ;
RelativeEntityMoveLook . m_Yaw = ( char ) ( ( GetRotation ( ) / 360.f ) * 256 ) ;
RelativeEntityMoveLook . m_Pitch = ( char ) ( ( GetPitch ( ) / 360.f ) * 256 ) ;
InChunk - > Broadcast ( RelativeEntityMoveLook , m_ClientHandle ) ;
}
else
{
cPacket_RelativeEntityMove RelativeEntityMove ;
RelativeEntityMove . m_UniqueID = GetUniqueID ( ) ;
RelativeEntityMove . m_MoveX = ( char ) ( DiffX * 32 ) ;
RelativeEntityMove . m_MoveY = ( char ) ( DiffY * 32 ) ;
RelativeEntityMove . m_MoveZ = ( char ) ( DiffZ * 32 ) ;
InChunk - > Broadcast ( RelativeEntityMove , m_ClientHandle ) ;
}
}
m_LastPosX = GetPosX ( ) ;
m_LastPosY = GetPosY ( ) ;
m_LastPosZ = GetPosZ ( ) ;
m_bDirtyPosition = false ;
m_ClientHandle - > StreamChunks ( ) ;
}
if ( m_Health > 0 ) // make sure player is alive
{
2012-02-13 16:47:03 -05:00
// TODO: Don't only check in current chunks, but also close chunks (chunks within range)
GetWorld ( ) - > GetChunk ( m_ChunkX , m_ChunkY , m_ChunkZ ) - > CollectPickupsByPlayer ( this ) ;
2011-10-03 14:41:19 -04:00
}
2011-12-25 20:07:35 -05:00
2011-12-25 23:06:29 -05:00
cTimer t1 ;
2011-12-27 13:39:06 -05:00
// Send Player List (Once per m_LastPlayerListTime/1000 ms)
2012-02-02 16:13:24 -05:00
if ( m_LastPlayerListTime + cPlayer : : PLAYER_LIST_TIME_MS < = t1 . GetNowTime ( ) )
{
2012-02-13 16:47:03 -05:00
m_World - > SendPlayerList ( this ) ;
2011-12-25 23:06:29 -05:00
m_LastPlayerListTime = t1 . GetNowTime ( ) ;
2011-12-25 20:07:35 -05:00
}
2011-10-03 14:41:19 -04:00
}
2012-02-13 16:47:03 -05:00
2011-10-03 14:41:19 -04:00
void cPlayer : : SetTouchGround ( bool a_bTouchGround )
{
m_bTouchGround = a_bTouchGround ;
if ( ! m_bTouchGround )
{
2011-10-30 20:52:20 -04:00
cWorld * World = GetWorld ( ) ;
2012-02-15 17:50:00 -05:00
char BlockID = World - > GetBlock ( float2int ( m_Pos . x ) , float2int ( m_Pos . y ) , float2int ( m_Pos . z ) ) ;
2011-10-03 14:41:19 -04:00
if ( BlockID ! = E_BLOCK_AIR )
{
m_bTouchGround = true ;
}
if ( BlockID = = E_BLOCK_WATER | | BlockID = = E_BLOCK_STATIONARY_WATER | | BlockID = = E_BLOCK_LADDER | | BlockID = = E_BLOCK_TORCH )
{
2012-02-15 17:50:00 -05:00
m_LastGroundHeight = ( float ) m_Pos . y ;
2011-10-03 14:41:19 -04:00
}
}
if ( m_bTouchGround )
{
2012-02-15 17:50:00 -05:00
float Dist = ( float ) ( m_LastGroundHeight - m_Pos . y ) ;
2011-10-03 14:41:19 -04:00
if ( Dist > 4.f ) // Player dropped
{
int Damage = ( int ) ( Dist - 4.f ) ;
if ( Damage > 0 )
{
TakeDamage ( Damage , 0 ) ;
}
}
2012-02-15 17:50:00 -05:00
m_LastGroundHeight = ( float ) m_Pos . y ;
2011-10-03 14:41:19 -04:00
}
}
void cPlayer : : Heal ( int a_Health )
{
2011-12-27 21:10:05 -05:00
if ( m_Health < GetMaxHealth ( ) )
2011-10-03 14:41:19 -04:00
{
2011-12-27 21:10:05 -05:00
m_Health = ( short ) MIN ( a_Health + m_Health , GetMaxHealth ( ) ) ;
2011-10-03 14:41:19 -04:00
cPacket_UpdateHealth Health ;
Health . m_Health = m_Health ;
2011-12-29 10:31:48 -05:00
Health . m_Food = GetFood ( ) ;
Health . m_Saturation = GetFoodSaturation ( ) ;
m_ClientHandle - > Send ( Health ) ;
}
}
void cPlayer : : Feed ( short a_Food )
{
if ( m_FoodLevel < GetMaxFoodLevel ( ) )
{
m_FoodLevel = MIN ( a_Food + m_FoodLevel , GetMaxFoodLevel ( ) ) ;
cPacket_UpdateHealth Health ;
Health . m_Health = m_Health ;
Health . m_Food = GetFood ( ) ;
Health . m_Saturation = GetFoodSaturation ( ) ;
2011-10-03 14:41:19 -04:00
m_ClientHandle - > Send ( Health ) ;
}
}
void cPlayer : : TakeDamage ( int a_Damage , cEntity * a_Instigator )
{
2011-11-01 16:26:11 -04:00
if ( ! ( m_GameMode = = 1 ) ) {
2011-10-26 15:13:49 -04:00
cPawn : : TakeDamage ( a_Damage , a_Instigator ) ;
2011-10-03 14:41:19 -04:00
2011-10-26 15:13:49 -04:00
cPacket_UpdateHealth Health ;
Health . m_Health = m_Health ;
2011-12-29 10:31:48 -05:00
Health . m_Food = GetFood ( ) ;
Health . m_Saturation = GetFoodSaturation ( ) ;
2011-12-21 15:42:34 -05:00
//TODO: Causes problems sometimes O.o (E.G. Disconnecting when attacked)
if ( m_ClientHandle ! = 0 )
m_ClientHandle - > Send ( Health ) ;
2011-10-26 15:13:49 -04:00
}
2011-10-03 14:41:19 -04:00
}
void cPlayer : : KilledBy ( cEntity * a_Killer )
{
cPawn : : KilledBy ( a_Killer ) ;
if ( m_Health > 0 ) return ; // not dead yet =]
m_bVisible = false ; // So new clients don't see the player
2011-12-26 04:09:47 -05:00
MTRand r1 ;
2011-10-03 14:41:19 -04:00
// Puke out all the items
cItem * Items = m_Inventory - > GetSlots ( ) ;
for ( unsigned int i = 1 ; i < m_Inventory - > c_NumSlots ; + + i )
{
if ( ! Items [ i ] . IsEmpty ( ) )
{
2011-12-26 04:09:47 -05:00
float SpeedX = ( ( r1 . randInt ( ) % 1000 ) - 500 ) / 100.f ;
float SpeedY = ( ( r1 . randInt ( ) % 1000 ) ) / 100.f ;
float SpeedZ = ( ( r1 . randInt ( ) % 1000 ) - 500 ) / 100.f ;
2012-02-15 17:50:00 -05:00
cPickup * Pickup = new cPickup ( ( int ) ( m_Pos . x * 32 ) , ( int ) ( m_Pos . y * 32 ) , ( int ) ( m_Pos . z * 32 ) , Items [ i ] , SpeedX , SpeedY , SpeedZ ) ;
2011-10-30 20:52:20 -04:00
Pickup - > Initialize ( GetWorld ( ) ) ;
2011-10-03 14:41:19 -04:00
}
Items [ i ] . Empty ( ) ;
}
SaveToDisk ( ) ; // Save it, yeah the world is a tough place !
}
void cPlayer : : Respawn ( )
{
2011-12-27 21:10:05 -05:00
m_Health = GetMaxHealth ( ) ;
2011-10-03 14:41:19 -04:00
2011-10-26 16:52:19 -04:00
// Create Respawn player packet
cPacket_Respawn Packet ;
//Set Gamemode for packet by looking at world's gamemode (Need to check players gamemode.)
2011-11-01 16:09:13 -04:00
//Packet.m_CreativeMode = (char)GetWorld()->GetGameMode();
Packet . m_CreativeMode = ( char ) m_GameMode ; //Set GameMode packet based on Player's GameMode;
2011-12-27 21:10:05 -05:00
//TODO Less hardcoded
Packet . m_World = 0 ;
Packet . m_MapSeed = GetWorld ( ) - > GetWorldSeed ( ) ;
2011-10-26 16:52:19 -04:00
//Send Packet
m_ClientHandle - > Send ( Packet ) ;
2011-12-27 21:10:05 -05:00
//Set non Burning
SetMetaData ( NORMAL ) ;
2011-10-30 20:52:20 -04:00
TeleportTo ( GetWorld ( ) - > GetSpawnX ( ) , GetWorld ( ) - > GetSpawnY ( ) , GetWorld ( ) - > GetSpawnZ ( ) ) ;
2011-12-27 21:10:05 -05:00
2011-10-03 14:41:19 -04:00
SetVisible ( true ) ;
}
double cPlayer : : GetEyeHeight ( )
{
return m_Stance ;
}
Vector3d cPlayer : : GetEyePosition ( )
{
2012-02-15 17:50:00 -05:00
return Vector3d ( m_Pos . x , m_Stance , m_Pos . z ) ;
2011-10-03 14:41:19 -04:00
}
void cPlayer : : OpenWindow ( cWindow * a_Window )
{
2011-12-25 09:03:01 -05:00
CloseWindow ( m_CurrentWindow ? ( char ) m_CurrentWindow - > GetWindowType ( ) : 0 ) ;
2011-10-03 14:41:19 -04:00
a_Window - > Open ( * this ) ;
m_CurrentWindow = a_Window ;
}
2011-12-25 20:07:35 -05:00
void cPlayer : : CloseWindow ( char a_WindowType )
2011-10-03 14:41:19 -04:00
{
2011-12-29 08:16:23 -05:00
if ( a_WindowType = = 0 ) { // Inventory
2011-12-31 23:55:17 -05:00
if ( m_Inventory - > GetWindow ( ) - > GetDraggingItem ( ) & & m_Inventory - > GetWindow ( ) - > GetDraggingItem ( ) - > m_ItemCount > 0 )
2011-12-25 09:03:01 -05:00
{
LOG ( " Player holds item! Dropping it... " ) ;
2011-12-31 23:55:17 -05:00
TossItem ( true , m_Inventory - > GetWindow ( ) - > GetDraggingItem ( ) - > m_ItemCount ) ;
2011-12-25 09:03:01 -05:00
}
//Drop whats in the crafting slots (1, 2, 3, 4)
for ( int i = 1 ; i < = 4 ; i + + )
{
cItem * Item = m_Inventory - > GetSlot ( i ) ;
if ( Item - > m_ItemID > 0 & & Item - > m_ItemCount > 0 )
{
float vX = 0 , vY = 0 , vZ = 0 ;
EulerToVector ( - GetRotation ( ) , GetPitch ( ) , vZ , vX , vY ) ;
vY = - vY * 2 + 1.f ;
cPickup * Pickup = new cPickup ( ( int ) ( GetPosX ( ) * 32 ) , ( int ) ( GetPosY ( ) * 32 ) + ( int ) ( 1.6f * 32 ) , ( int ) ( GetPosZ ( ) * 32 ) , * Item , vX * 2 , vY * 2 , vZ * 2 ) ;
Pickup - > Initialize ( GetWorld ( ) ) ;
}
Item - > Empty ( ) ;
}
}
2012-01-01 13:45:28 -05:00
if ( m_CurrentWindow )
{
if ( a_WindowType = = 1 & & strcmp ( m_CurrentWindow - > GetWindowTitle ( ) . c_str ( ) , " UberChest " ) = = 0 ) { // Chest
cBlockEntity * block = m_CurrentWindow - > GetOwner ( ) - > GetEntity ( ) ;
cPacket_BlockAction ChestClose ;
ChestClose . m_PosX = block - > GetPosX ( ) ;
ChestClose . m_PosY = ( short ) block - > GetPosY ( ) ;
ChestClose . m_PosZ = block - > GetPosZ ( ) ;
ChestClose . m_Byte1 = 1 ;
ChestClose . m_Byte2 = 0 ;
2012-02-13 16:47:03 -05:00
m_World - > Broadcast ( ChestClose ) ;
2011-12-29 08:16:23 -05:00
}
2012-01-01 13:45:28 -05:00
m_CurrentWindow - > Close ( * this ) ;
2011-12-29 08:16:23 -05:00
}
2012-02-13 16:47:03 -05:00
m_CurrentWindow = NULL ;
2011-10-03 14:41:19 -04:00
}
2012-02-13 16:47:03 -05:00
2011-11-01 16:09:13 -04:00
void cPlayer : : SetLastBlockActionTime ( )
{
m_LastBlockActionTime = cRoot : : Get ( ) - > GetWorld ( ) - > GetTime ( ) ;
}
2012-02-13 16:47:03 -05:00
2011-11-10 11:30:14 -05:00
void cPlayer : : SetLastBlockActionCnt ( int a_LastBlockActionCnt )
{
m_LastBlockActionCnt = a_LastBlockActionCnt ;
}
2012-02-13 16:47:03 -05:00
2011-11-01 16:09:13 -04:00
void cPlayer : : SetGameMode ( int a_GameMode )
{
2012-01-01 13:45:28 -05:00
if ( ( a_GameMode < 2 ) & & ( a_GameMode > = 0 ) )
{
if ( m_GameMode ! = a_GameMode )
{
cInventory * OldInventory = 0 ;
if ( m_GameMode = = 0 )
OldInventory = m_Inventory ;
else
OldInventory = m_CreativeInventory ;
2011-11-10 13:28:21 -05:00
m_GameMode = a_GameMode ;
cPacket_NewInvalidState GameModePacket ;
GameModePacket . m_Reason = 3 ; //GameModeChange
GameModePacket . m_GameMode = ( char ) a_GameMode ; //GameModeChange
m_ClientHandle - > Send ( GameModePacket ) ;
2011-12-31 23:55:17 -05:00
GetInventory ( ) . SendWholeInventory ( m_ClientHandle ) ;
2012-01-01 13:45:28 -05:00
OldInventory - > SetEquippedSlot ( GetInventory ( ) . GetEquippedSlot ( ) ) ;
2011-11-10 13:28:21 -05:00
}
}
}
2012-02-13 16:47:03 -05:00
2011-11-10 13:28:21 -05:00
void cPlayer : : LoginSetGameMode ( int a_GameMode )
{
m_GameMode = a_GameMode ;
2011-11-01 16:09:13 -04:00
}
2012-02-13 16:47:03 -05:00
2011-11-09 17:17:30 -05:00
void cPlayer : : SetIP ( std : : string a_IP )
{
2012-02-13 16:47:03 -05:00
m_IP = a_IP ;
2011-11-09 17:17:30 -05:00
}
2011-11-01 16:09:13 -04:00
2012-02-13 16:47:03 -05:00
2011-10-03 14:41:19 -04:00
void cPlayer : : SendMessage ( const char * a_Message )
{
m_ClientHandle - > Send ( cPacket_Chat ( a_Message ) ) ;
}
2012-02-13 16:47:03 -05:00
2011-10-03 14:41:19 -04:00
void cPlayer : : TeleportTo ( const double & a_PosX , const double & a_PosY , const double & a_PosZ )
{
2011-12-27 21:10:05 -05:00
SetPosition ( a_PosX , a_PosY , a_PosZ ) ;
cPacket_TeleportEntity TeleportEntity ( this ) ;
cRoot : : Get ( ) - > GetServer ( ) - > Broadcast ( TeleportEntity , GetClientHandle ( ) ) ;
2011-10-03 14:41:19 -04:00
cPacket_PlayerPosition PlayerPosition ( this ) ;
2011-12-27 21:10:05 -05:00
2011-10-03 14:41:19 -04:00
m_ClientHandle - > Send ( PlayerPosition ) ;
}
2012-02-13 16:47:03 -05:00
2011-10-03 14:41:19 -04:00
void cPlayer : : MoveTo ( const Vector3d & a_NewPos )
{
// TODO: should do some checks to see if player is not moving through terrain
SetPosition ( a_NewPos ) ;
}
2012-02-13 16:47:03 -05:00
2011-10-03 14:41:19 -04:00
void cPlayer : : SetVisible ( bool a_bVisible )
{
2012-02-13 16:47:03 -05:00
if ( a_bVisible & & ! m_bVisible ) // Make visible
2011-10-03 14:41:19 -04:00
{
m_bVisible = true ;
2012-02-13 16:47:03 -05:00
SpawnOn ( NULL ) ; // Spawn on everybody
2011-10-03 14:41:19 -04:00
}
2012-02-13 16:47:03 -05:00
if ( ! a_bVisible & & m_bVisible )
2011-10-03 14:41:19 -04:00
{
m_bVisible = false ;
cPacket_DestroyEntity DestroyEntity ( this ) ;
2012-02-13 16:47:03 -05:00
cChunkPtr Chunk = GetWorld ( ) - > GetChunk ( m_ChunkX , m_ChunkY , m_ChunkZ ) ;
if ( Chunk ! = NULL )
2011-10-03 14:41:19 -04:00
{
Chunk - > Broadcast ( DestroyEntity ) ; // Destroy on all clients
}
}
}
2012-02-13 16:47:03 -05:00
2011-10-03 14:41:19 -04:00
void cPlayer : : AddToGroup ( const char * a_GroupName )
{
cGroup * Group = cRoot : : Get ( ) - > GetGroupManager ( ) - > GetGroup ( a_GroupName ) ;
m_pState - > Groups . push_back ( Group ) ;
LOG ( " Added %s to group %s " , m_pState - > PlayerName . c_str ( ) , a_GroupName ) ;
ResolveGroups ( ) ;
ResolvePermissions ( ) ;
}
bool cPlayer : : CanUseCommand ( const char * a_Command )
{
for ( GroupList : : iterator itr = m_pState - > Groups . begin ( ) ; itr ! = m_pState - > Groups . end ( ) ; + + itr )
{
if ( ( * itr ) - > HasCommand ( a_Command ) ) return true ;
}
return false ;
}
2012-02-01 04:12:54 -05:00
2011-10-03 14:41:19 -04:00
bool cPlayer : : HasPermission ( const char * a_Permission )
{
2012-02-01 04:12:54 -05:00
AStringVector Split = StringSplit ( a_Permission , " . " ) ;
2011-10-03 14:41:19 -04:00
PermissionMap Possibilities = m_pState - > ResolvedPermissions ;
// Now search the namespaces
while ( Possibilities . begin ( ) ! = Possibilities . end ( ) )
{
PermissionMap : : iterator itr = Possibilities . begin ( ) ;
if ( itr - > second )
{
2012-02-01 04:12:54 -05:00
AStringVector OtherSplit = StringSplit ( itr - > first , " . " ) ;
2011-10-03 14:41:19 -04:00
if ( OtherSplit . size ( ) < = Split . size ( ) )
{
unsigned int i ;
for ( i = 0 ; i < OtherSplit . size ( ) ; + + i )
{
if ( OtherSplit [ i ] . compare ( Split [ i ] ) ! = 0 )
{
if ( OtherSplit [ i ] . compare ( " * " ) = = 0 ) return true ; // WildCard man!! WildCard!
break ;
}
}
if ( i = = Split . size ( ) ) return true ;
}
}
Possibilities . erase ( itr ) ;
}
// Nothing that matched :(
return false ;
}
2012-02-01 04:12:54 -05:00
2011-10-03 14:41:19 -04:00
bool cPlayer : : IsInGroup ( const char * a_Group )
{
for ( GroupList : : iterator itr = m_pState - > ResolvedGroups . begin ( ) ; itr ! = m_pState - > ResolvedGroups . end ( ) ; + + itr )
{
if ( strcmp ( a_Group , ( * itr ) - > GetName ( ) . c_str ( ) ) = = 0 )
return true ;
}
return false ;
}
void cPlayer : : ResolvePermissions ( )
{
m_pState - > ResolvedPermissions . clear ( ) ; // Start with an empty map yo~
// Copy all player specific permissions into the resolved permissions map
for ( PermissionMap : : iterator itr = m_pState - > Permissions . begin ( ) ; itr ! = m_pState - > Permissions . end ( ) ; + + itr )
{
m_pState - > ResolvedPermissions [ itr - > first ] = itr - > second ;
}
for ( GroupList : : iterator GroupItr = m_pState - > ResolvedGroups . begin ( ) ; GroupItr ! = m_pState - > ResolvedGroups . end ( ) ; + + GroupItr )
{
const cGroup : : PermissionMap & Permissions = ( * GroupItr ) - > GetPermissions ( ) ;
for ( cGroup : : PermissionMap : : const_iterator itr = Permissions . begin ( ) ; itr ! = Permissions . end ( ) ; + + itr )
{
m_pState - > ResolvedPermissions [ itr - > first ] = itr - > second ;
}
}
}
2012-02-13 16:47:03 -05:00
2011-10-03 14:41:19 -04:00
void cPlayer : : ResolveGroups ( )
{
// Clear resolved groups first
m_pState - > ResolvedGroups . clear ( ) ;
// Get a complete resolved list of all groups the player is in
std : : map < cGroup * , bool > AllGroups ; // Use a map, because it's faster than iterating through a list to find duplicates
GroupList ToIterate ;
for ( GroupList : : iterator GroupItr = m_pState - > Groups . begin ( ) ; GroupItr ! = m_pState - > Groups . end ( ) ; + + GroupItr )
{
ToIterate . push_back ( * GroupItr ) ;
}
while ( ToIterate . begin ( ) ! = ToIterate . end ( ) )
{
cGroup * CurrentGroup = * ToIterate . begin ( ) ;
if ( AllGroups . find ( CurrentGroup ) ! = AllGroups . end ( ) )
{
LOGERROR ( " ERROR: Player %s is in the same group multiple times (%s). FIX IT! " , m_pState - > PlayerName . c_str ( ) , CurrentGroup - > GetName ( ) . c_str ( ) ) ;
}
else
{
AllGroups [ CurrentGroup ] = true ;
m_pState - > ResolvedGroups . push_back ( CurrentGroup ) ; // Add group to resolved list
const cGroup : : GroupList & Inherits = CurrentGroup - > GetInherits ( ) ;
for ( cGroup : : GroupList : : const_iterator itr = Inherits . begin ( ) ; itr ! = Inherits . end ( ) ; + + itr )
{
if ( AllGroups . find ( * itr ) ! = AllGroups . end ( ) )
{
LOGERROR ( " ERROR: Player %s is in the same group multiple times due to inheritance (%s). FIX IT! " , m_pState - > PlayerName . c_str ( ) , ( * itr ) - > GetName ( ) . c_str ( ) ) ;
continue ;
}
ToIterate . push_back ( * itr ) ;
}
}
ToIterate . erase ( ToIterate . begin ( ) ) ;
}
}
2012-02-13 16:47:03 -05:00
AString cPlayer : : GetColor ( void ) const
2011-10-03 14:41:19 -04:00
{
2012-02-13 16:47:03 -05:00
if ( m_Color ! = ' - ' )
{
2011-10-03 14:41:19 -04:00
return cChatColor : : MakeColor ( m_Color ) ;
2012-02-13 16:47:03 -05:00
}
2011-10-03 14:41:19 -04:00
2012-02-13 16:47:03 -05:00
if ( m_pState - > Groups . size ( ) < 1 )
{
2011-10-03 14:41:19 -04:00
return cChatColor : : White ;
2012-02-13 16:47:03 -05:00
}
2011-10-03 14:41:19 -04:00
return ( * m_pState - > Groups . begin ( ) ) - > GetColor ( ) ;
}
2012-02-13 16:47:03 -05:00
2011-10-03 14:41:19 -04:00
void cPlayer : : TossItem ( bool a_bDraggingItem , int a_Amount /* = 1 */ )
{
if ( a_bDraggingItem )
{
2012-01-01 13:45:28 -05:00
cItem * Item = GetInventory ( ) . GetWindow ( ) - > GetDraggingItem ( ) ;
2011-10-03 14:41:19 -04:00
if ( Item - > m_ItemID > 0 & & Item - > m_ItemCount > = a_Amount )
{
float vX = 0 , vY = 0 , vZ = 0 ;
EulerToVector ( - GetRotation ( ) , GetPitch ( ) , vZ , vX , vY ) ;
vY = - vY * 2 + 1.f ;
cPickup * Pickup = new cPickup ( ( int ) ( GetPosX ( ) * 32 ) , ( int ) ( GetPosY ( ) * 32 ) + ( int ) ( 1.6f * 32 ) , ( int ) ( GetPosZ ( ) * 32 ) , cItem ( Item - > m_ItemID , ( char ) a_Amount , Item - > m_ItemHealth ) , vX * 2 , vY * 2 , vZ * 2 ) ;
2011-10-30 20:52:20 -04:00
Pickup - > Initialize ( GetWorld ( ) ) ;
2011-10-03 14:41:19 -04:00
if ( Item - > m_ItemCount > a_Amount )
Item - > m_ItemCount - = ( char ) a_Amount ;
else
Item - > Empty ( ) ;
}
return ;
}
// Else drop equipped item
cItem DroppedItem = GetInventory ( ) . GetEquippedItem ( ) ;
if ( DroppedItem . m_ItemID > 0 & & DroppedItem . m_ItemCount > 0 )
{
DroppedItem . m_ItemCount = 1 ;
if ( GetInventory ( ) . RemoveItem ( DroppedItem ) )
{
DroppedItem . m_ItemCount = 1 ; // RemoveItem decreases the count, so set it to 1 again
float vX = 0 , vY = 0 , vZ = 0 ;
EulerToVector ( - GetRotation ( ) , GetPitch ( ) , vZ , vX , vY ) ;
vY = - vY * 2 + 1.f ;
cPickup * Pickup = new cPickup ( ( int ) ( GetPosX ( ) * 32 ) , ( int ) ( GetPosY ( ) * 32 ) + ( int ) ( 1.6f * 32 ) , ( int ) ( GetPosZ ( ) * 32 ) , DroppedItem , vX * 2 , vY * 2 , vZ * 2 ) ;
2011-10-30 20:52:20 -04:00
Pickup - > Initialize ( GetWorld ( ) ) ;
2011-10-03 14:41:19 -04:00
}
}
}
2012-02-13 16:47:03 -05:00
2011-12-26 16:54:08 -05:00
bool cPlayer : : MoveToWorld ( const char * a_WorldName )
{
2012-02-13 16:47:03 -05:00
cWorld * World = cRoot : : Get ( ) - > GetWorld ( a_WorldName ) ;
if ( World )
2011-12-26 16:54:08 -05:00
{
/* Remove all links to the old world */
2012-02-13 16:47:03 -05:00
m_World - > RemovePlayer ( this ) ;
m_ClientHandle - > RemoveFromAllChunks ( ) ;
cChunkPtr Chunk = m_World - > GetChunk ( m_ChunkX , m_ChunkY , m_ChunkZ ) ;
if ( Chunk ! = NULL )
2011-12-26 16:54:08 -05:00
{
2012-02-13 16:47:03 -05:00
Chunk - > RemoveEntity ( this ) ;
2011-12-26 16:54:08 -05:00
Chunk - > Broadcast ( cPacket_DestroyEntity ( this ) ) ; // Remove player entity from all clients in old world
}
/* Add player to all the necessary parts of the new world */
SetWorld ( World ) ;
GetWorld ( ) - > AddPlayer ( this ) ;
MoveToCorrectChunk ( true ) ;
GetClientHandle ( ) - > StreamChunks ( ) ;
return true ;
}
return false ;
}
2012-02-13 16:47:03 -05:00
2012-01-30 11:47:26 -05:00
void cPlayer : : LoadPermissionsFromDisk ( )
2011-10-03 14:41:19 -04:00
{
2012-01-30 11:47:26 -05:00
m_pState - > Groups . clear ( ) ;
m_pState - > Permissions . clear ( ) ;
2011-10-03 14:41:19 -04:00
cIniFile IniFile ( " users.ini " ) ;
if ( IniFile . ReadFile ( ) )
{
std : : string Groups = IniFile . GetValue ( m_pState - > PlayerName , " Groups " , " " ) ;
if ( Groups . size ( ) > 0 )
{
2012-02-01 04:12:54 -05:00
AStringVector Split = StringSplit ( Groups , " , " ) ;
2011-10-03 14:41:19 -04:00
for ( unsigned int i = 0 ; i < Split . size ( ) ; i + + )
{
AddToGroup ( Split [ i ] . c_str ( ) ) ;
}
}
else
{
AddToGroup ( " Default " ) ;
}
m_Color = IniFile . GetValue ( m_pState - > PlayerName , " Color " , " - " ) [ 0 ] ;
}
else
{
2011-12-27 17:57:33 -05:00
LOGWARN ( " WARNING: Failed to read ini file users.ini " ) ;
2011-10-03 14:41:19 -04:00
AddToGroup ( " Default " ) ;
}
ResolvePermissions ( ) ;
2012-01-30 11:47:26 -05:00
}
2012-01-30 17:48:38 -05:00
2012-01-30 19:38:18 -05:00
bool cPlayer : : LoadFromDisk ( )
2012-01-30 11:47:26 -05:00
{
LoadPermissionsFromDisk ( ) ;
2011-10-03 14:41:19 -04:00
// Log player permissions, cause it's what the cool kids do
LOGINFO ( " Player %s has permissions: " , m_pState - > PlayerName . c_str ( ) ) ;
for ( PermissionMap : : iterator itr = m_pState - > ResolvedPermissions . begin ( ) ; itr ! = m_pState - > ResolvedPermissions . end ( ) ; + + itr )
{
if ( itr - > second ) LOGINFO ( " %s " , itr - > first . c_str ( ) ) ;
}
2012-02-01 08:43:47 -05:00
AString SourceFile ;
Printf ( SourceFile , " players/%s.json " , m_pState - > PlayerName . c_str ( ) ) ;
2011-10-03 14:41:19 -04:00
2012-01-30 17:48:38 -05:00
cFile f ;
if ( ! f . Open ( SourceFile , cFile : : fmRead ) )
{
return false ;
}
2011-10-31 17:30:14 -04:00
2012-01-30 17:48:38 -05:00
// Get file size
long FileSize = f . GetSize ( ) ;
2011-10-31 17:30:14 -04:00
2012-02-01 08:43:47 -05:00
std : : auto_ptr < char > buffer ( new char [ FileSize ] ) ;
if ( f . Read ( buffer . get ( ) , FileSize ) ! = FileSize )
2012-01-30 17:48:38 -05:00
{
2012-02-01 09:08:12 -05:00
LOGERROR ( " ERROR READING FROM FILE \" %s \" " , SourceFile . c_str ( ) ) ;
2012-01-30 17:48:38 -05:00
return false ;
}
f . Close ( ) ;
2011-11-02 16:19:57 -04:00
2012-01-30 17:48:38 -05:00
Json : : Value root ;
Json : : Reader reader ;
2012-02-01 08:43:47 -05:00
if ( ! reader . parse ( buffer . get ( ) , root , false ) )
2012-01-30 17:48:38 -05:00
{
2012-02-01 09:08:12 -05:00
LOGERROR ( " ERROR WHILE PARSING JSON FROM FILE %s " , SourceFile . c_str ( ) ) ;
2012-01-30 17:48:38 -05:00
}
2011-10-31 17:30:14 -04:00
2012-02-01 08:43:47 -05:00
buffer . reset ( ) ;
2012-01-30 17:48:38 -05:00
Json : : Value & JSON_PlayerPosition = root [ " position " ] ;
if ( JSON_PlayerPosition . size ( ) = = 3 )
{
2012-02-15 17:50:00 -05:00
m_Pos . x = JSON_PlayerPosition [ ( unsigned int ) 0 ] . asDouble ( ) ;
m_Pos . y = JSON_PlayerPosition [ ( unsigned int ) 1 ] . asDouble ( ) ;
m_Pos . z = JSON_PlayerPosition [ ( unsigned int ) 2 ] . asDouble ( ) ;
2011-10-03 14:41:19 -04:00
}
2012-01-30 17:48:38 -05:00
Json : : Value & JSON_PlayerRotation = root [ " rotation " ] ;
if ( JSON_PlayerRotation . size ( ) = = 3 )
{
2012-02-15 17:50:00 -05:00
m_Rot . x = ( float ) JSON_PlayerRotation [ ( unsigned int ) 0 ] . asDouble ( ) ;
m_Rot . y = ( float ) JSON_PlayerRotation [ ( unsigned int ) 1 ] . asDouble ( ) ;
m_Rot . z = ( float ) JSON_PlayerRotation [ ( unsigned int ) 2 ] . asDouble ( ) ;
2012-01-30 17:48:38 -05:00
}
m_Health = ( short ) root . get ( " health " , 0 ) . asInt ( ) ;
m_FoodLevel = ( short ) root . get ( " food " , 0 ) . asInt ( ) ;
m_Inventory - > LoadFromJson ( root [ " inventory " ] ) ;
m_CreativeInventory - > LoadFromJson ( root [ " creativeinventory " ] ) ;
m_pState - > LoadedWorldName = root . get ( " world " , " world " ) . asString ( ) ;
return true ;
2011-10-03 14:41:19 -04:00
}
2012-01-30 17:48:38 -05:00
2011-10-03 14:41:19 -04:00
bool cPlayer : : SaveToDisk ( )
{
2011-11-01 17:57:08 -04:00
cMakeDir : : MakeDir ( " players " ) ;
2011-10-03 14:41:19 -04:00
2011-10-31 17:30:14 -04:00
// create the JSON data
Json : : Value JSON_PlayerPosition ;
2012-02-15 17:50:00 -05:00
JSON_PlayerPosition . append ( Json : : Value ( m_Pos . x ) ) ;
JSON_PlayerPosition . append ( Json : : Value ( m_Pos . y ) ) ;
JSON_PlayerPosition . append ( Json : : Value ( m_Pos . z ) ) ;
2011-10-31 17:30:14 -04:00
Json : : Value JSON_PlayerRotation ;
2012-02-15 17:50:00 -05:00
JSON_PlayerRotation . append ( Json : : Value ( m_Rot . x ) ) ;
JSON_PlayerRotation . append ( Json : : Value ( m_Rot . y ) ) ;
JSON_PlayerRotation . append ( Json : : Value ( m_Rot . z ) ) ;
2011-10-31 17:30:14 -04:00
Json : : Value JSON_Inventory ;
m_Inventory - > SaveToJson ( JSON_Inventory ) ;
2012-01-01 13:45:28 -05:00
Json : : Value JSON_CreativeInventory ;
m_CreativeInventory - > SaveToJson ( JSON_CreativeInventory ) ;
2011-10-31 17:30:14 -04:00
Json : : Value root ;
root [ " position " ] = JSON_PlayerPosition ;
root [ " rotation " ] = JSON_PlayerRotation ;
root [ " inventory " ] = JSON_Inventory ;
2012-01-01 13:45:28 -05:00
root [ " creativeinventory " ] = JSON_CreativeInventory ;
2011-10-31 17:30:14 -04:00
root [ " health " ] = m_Health ;
2011-12-29 10:31:48 -05:00
root [ " food " ] = m_FoodLevel ;
2011-11-02 16:19:57 -04:00
root [ " world " ] = GetWorld ( ) - > GetName ( ) ;
2011-10-31 17:30:14 -04:00
Json : : StyledWriter writer ;
std : : string JsonData = writer . write ( root ) ;
2012-02-01 08:43:47 -05:00
AString SourceFile ;
Printf ( SourceFile , " players/%s.json " , m_pState - > PlayerName . c_str ( ) ) ;
2011-10-03 14:41:19 -04:00
2012-01-30 17:48:38 -05:00
cFile f ;
if ( ! f . Open ( SourceFile , cFile : : fmWrite ) )
2011-10-03 14:41:19 -04:00
{
2012-02-01 09:08:12 -05:00
LOGERROR ( " ERROR WRITING PLAYER \" %s \" TO FILE \" %s \" - cannot open file " , m_pState - > PlayerName . c_str ( ) , SourceFile . c_str ( ) ) ;
2012-01-30 17:48:38 -05:00
return false ;
2011-10-03 14:41:19 -04:00
}
2012-01-30 17:48:38 -05:00
if ( f . Write ( JsonData . c_str ( ) , JsonData . size ( ) ) ! = JsonData . size ( ) )
{
2012-02-01 09:08:12 -05:00
LOGERROR ( " ERROR WRITING PLAYER JSON TO FILE \" %s \" " , SourceFile . c_str ( ) ) ;
2012-01-30 17:48:38 -05:00
return false ;
}
return true ;
2011-10-03 14:41:19 -04:00
}
2012-01-30 17:48:38 -05:00
2012-02-01 17:38:03 -05:00
const AString & cPlayer : : GetName ( void ) const
2011-10-03 14:41:19 -04:00
{
2012-02-01 17:38:03 -05:00
return m_pState - > PlayerName ;
2011-10-03 14:41:19 -04:00
}
2012-02-01 17:38:03 -05:00
void cPlayer : : SetName ( const AString & a_Name )
2011-10-03 14:41:19 -04:00
{
m_pState - > PlayerName = a_Name ;
}
2012-02-01 17:38:03 -05:00
2011-10-03 14:41:19 -04:00
const cPlayer : : GroupList & cPlayer : : GetGroups ( )
{
return m_pState - > Groups ;
2011-10-26 15:13:49 -04:00
}
2011-11-02 16:19:57 -04:00
2012-02-02 02:47:19 -05:00
2012-01-30 11:47:26 -05:00
cPlayer : : StringList cPlayer : : GetResolvedPermissions ( )
{
StringList Permissions ;
const PermissionMap & ResolvedPermissions = m_pState - > ResolvedPermissions ;
for ( PermissionMap : : const_iterator itr = ResolvedPermissions . begin ( ) ; itr ! = ResolvedPermissions . end ( ) ; + + itr )
{
if ( itr - > second ) Permissions . push_back ( itr - > first ) ;
}
return Permissions ;
}
2012-02-02 02:47:19 -05:00
2011-11-02 16:19:57 -04:00
const char * cPlayer : : GetLoadedWorldName ( )
{
return m_pState - > LoadedWorldName . c_str ( ) ;
2011-12-28 16:00:35 -05:00
}
2012-02-02 02:47:19 -05:00
2011-12-28 16:00:35 -05:00
void cPlayer : : UseEquippedItem ( )
{
if ( GetGameMode ( ) ! = 1 ) //No damage in creative
2012-02-02 02:47:19 -05:00
{
2011-12-28 16:00:35 -05:00
if ( GetInventory ( ) . GetEquippedItem ( ) . DamageItem ( ) )
{
2012-02-01 17:38:03 -05:00
LOG ( " Player %s Broke ID: %i " , GetClientHandle ( ) - > GetUsername ( ) . c_str ( ) , GetInventory ( ) . GetEquippedItem ( ) . m_ItemID ) ;
2011-12-28 16:00:35 -05:00
GetInventory ( ) . RemoveItem ( GetInventory ( ) . GetEquippedItem ( ) ) ;
}
2012-02-02 02:47:19 -05:00
}
}