Merged ryzom/ryzomcore into default

This commit is contained in:
StudioEtrange 2013-09-07 20:16:17 +02:00
commit 3721135484
10 changed files with 119 additions and 180 deletions

View file

@ -1,50 +0,0 @@
# - Locate S3TC library
# This module defines
# S3TC_LIBRARY, the library to link against
# S3TC_FOUND, if false, do not try to link to S3TC
# S3TC_INCLUDE_DIR, where to find headers.
IF(S3TC_LIBRARY AND S3TC_INCLUDE_DIR)
# in cache already
SET(S3TC_FIND_QUIETLY TRUE)
ENDIF(S3TC_LIBRARY AND S3TC_INCLUDE_DIR)
FIND_PATH(S3TC_INCLUDE_DIR
s3_intrf.h
PATHS
$ENV{S3TC_DIR}/include
/usr/local/include
/usr/include
/sw/include
/opt/local/include
/opt/csw/include
/opt/include
PATH_SUFFIXES S3TC
)
FIND_LIBRARY(S3TC_LIBRARY
NAMES s3tc libs3tc
PATHS
$ENV{S3TC_DIR}/lib
/usr/local/lib
/usr/lib
/usr/local/X11R6/lib
/usr/X11R6/lib
/sw/lib
/opt/local/lib
/opt/csw/lib
/opt/lib
/usr/freeware/lib64
)
IF(S3TC_LIBRARY AND S3TC_INCLUDE_DIR)
SET(S3TC_FOUND "YES")
IF(NOT S3TC_FIND_QUIETLY)
MESSAGE(STATUS "Found S3TC: ${S3TC_LIBRARY}")
ENDIF(NOT S3TC_FIND_QUIETLY)
ELSE(S3TC_LIBRARY AND S3TC_INCLUDE_DIR)
IF(NOT S3TC_FIND_QUIETLY)
MESSAGE(STATUS "Warning: Unable to find S3TC!")
ENDIF(NOT S3TC_FIND_QUIETLY)
ENDIF(S3TC_LIBRARY AND S3TC_INCLUDE_DIR)

View file

@ -19,6 +19,7 @@
#include "nel/misc/bitmap.h" #include "nel/misc/bitmap.h"
#include "nel/misc/stream.h" #include "nel/misc/stream.h"
#include "nel/misc/file.h" #include "nel/misc/file.h"
#include "nel/misc/system_info.h"
// Define this to force all bitmap white (debug) // Define this to force all bitmap white (debug)
// #define NEL_ALL_BITMAP_WHITE // #define NEL_ALL_BITMAP_WHITE

View file

@ -3552,12 +3552,13 @@ void CUserEntity::CSpeedFactor::update(ICDBNode *node) // virtual
//nlinfo("SpeedFactor changed to %f / %"NL_I64"u", _Value, leaf->getValue64()); //nlinfo("SpeedFactor changed to %f / %"NL_I64"u", _Value, leaf->getValue64());
// clamp the value (2.0 is the egg item or the level 6 speed up power up, nothing should be faster) // clamp the value (2.0 is the egg item or the level 6 speed up power up, nothing should be faster)
if(_Value > 2.0f) // commented because ring editor speed is in fact faster
{ //if(_Value > 2.0f)
//{
//nlwarning("HACK: you try to change the speed factor to %f", _Value); //nlwarning("HACK: you try to change the speed factor to %f", _Value);
//nlstop; //nlstop;
//_Value = 2.0f; //_Value = 2.0f;
} //}
}// CSpeedFactor::update // }// CSpeedFactor::update //

View file

@ -155,6 +155,11 @@ inline double CAIVectorMirror::distTo(const CAIPos &dest) const
return (dest-CAIVector(*this)).norm(); return (dest-CAIVector(*this)).norm();
} }
inline double CAIVectorMirror::distSqTo(const CAIPos &dest) const
{
return (dest-CAIVector(*this)).sqrnorm();
}
inline double CAIVectorMirror::quickDistTo(const CAIPos &dest) const inline double CAIVectorMirror::quickDistTo(const CAIPos &dest) const
{ {
double dx=fabs((dest.x()-x()).asDouble()), dy=fabs((dest.y()-y()).asDouble()); double dx=fabs((dest.x()-x()).asDouble()), dy=fabs((dest.y()-y()).asDouble());
@ -172,6 +177,11 @@ inline double CAIVectorMirror::distTo(const CAIVector &dest) const
return (dest-CAIVector(*this)).norm(); return (dest-CAIVector(*this)).norm();
} }
inline double CAIVectorMirror::distSqTo(const CAIVector &dest) const
{
return (dest-CAIVector(*this)).sqrnorm();
}
inline double CAIVectorMirror::quickDistTo(const CAIVector &dest) const inline double CAIVectorMirror::quickDistTo(const CAIVector &dest) const
{ {
double dx=fabs((dest.x()-x()).asDouble()), dy=fabs((dest.y()-y()).asDouble()); double dx=fabs((dest.x()-x()).asDouble()), dy=fabs((dest.y()-y()).asDouble());
@ -189,6 +199,11 @@ inline double CAIVectorMirror::distTo(const CAIVectorMirror &dest) const
return (dest-*this).norm(); return (dest-*this).norm();
} }
inline double CAIVectorMirror::distSqTo(const CAIVectorMirror &dest) const
{
return (dest-*this).sqrnorm();
}
inline double CAIVectorMirror::quickDistTo(const CAIVectorMirror &dest) const inline double CAIVectorMirror::quickDistTo(const CAIVectorMirror &dest) const
{ {
double dx=fabs((dest.x()-x()).asDouble()), dy=fabs((dest.y()-y()).asDouble()); return (dx>dy)? (dx+dy/2): (dy+dx/2); double dx=fabs((dest.x()-x()).asDouble()), dy=fabs((dest.y()-y()).asDouble()); return (dx>dy)? (dx+dy/2): (dy+dx/2);

View file

@ -310,9 +310,9 @@ void CWanderFaunaProfile::updateProfile(uint ticksSinceLastUpdate)
CFollowPathContext fpcWanderFaunaProfileUpdate("WanderFaunaProfileUpdate"); CFollowPathContext fpcWanderFaunaProfileUpdate("WanderFaunaProfileUpdate");
// calculate distance from bot position to magnet point (used in all the different processes) // calculate distance from bot position to magnet point (used in all the different processes)
_magnetDist=_Bot->pos().distTo(_Bot->spawnGrp().magnetPos()); _magnetDistSq=_Bot->pos().distSqTo(_Bot->spawnGrp().magnetPos());
double grpMagnetRadiusFar=_Bot->spawnGrp().magnetRadiusFar();
if (_magnetDist>_Bot->spawnGrp().magnetRadiusFar()) if (_magnetDistSq>(grpMagnetRadiusFar*grpMagnetRadiusFar))
{ {
_Bot->setMode( MBEHAV::NORMAL ); _Bot->setMode( MBEHAV::NORMAL );
@ -405,11 +405,12 @@ void CGrazeFaunaProfile::updateProfile(uint ticksSinceLastUpdate)
CFollowPathContext fpcGrazeFaunaProfileUpdate("GrazeFaunaProfileUpdate"); CFollowPathContext fpcGrazeFaunaProfileUpdate("GrazeFaunaProfileUpdate");
// calculate distance from bot position to magnet point (used in all the different processes) // calculate distance from bot position to magnet point (used in all the different processes)
_magnetDist=_Bot->pos().distTo(_Bot->spawnGrp().magnetPos()); _magnetDistSq=_Bot->pos().distSqTo(_Bot->spawnGrp().magnetPos());
if (!_ArrivedInZone) if (!_ArrivedInZone)
{ {
if (_magnetDist>_Bot->spawnGrp().magnetRadiusFar()) float grpMagnetRadiusFar=_Bot->spawnGrp().magnetRadiusFar();
if (_magnetDistSq>(grpMagnetRadiusFar*grpMagnetRadiusFar))
{ {
_Bot->setMode( MBEHAV::NORMAL ); _Bot->setMode( MBEHAV::NORMAL );
@ -501,7 +502,8 @@ void CGrazeFaunaProfile::updateProfile(uint ticksSinceLastUpdate)
} }
// && _state==0 ) // means wait in movementmagnet. // && _state==0 ) // means wait in movementmagnet.
if ( _magnetDist<=_Bot->spawnGrp().magnetRadiusNear() const float grpMagnetRadiusNear=_Bot->spawnGrp().magnetRadiusNear();
if ( _magnetDistSq<=(grpMagnetRadiusNear*grpMagnetRadiusNear)
&& _MovementMagnet->getMovementType()==CMovementMagnet::Movement_Anim) && _MovementMagnet->getMovementType()==CMovementMagnet::Movement_Anim)
{ {
if (_Bot->getPersistent().grp().getType()==AITYPES::FaunaTypePredator) if (_Bot->getPersistent().grp().getType()==AITYPES::FaunaTypePredator)
@ -564,11 +566,12 @@ void CRestFaunaProfile::updateProfile(uint ticksSinceLastUpdate)
CFollowPathContext fpcRestFaunaProfileUpdate("RestFaunaProfileUpdate"); CFollowPathContext fpcRestFaunaProfileUpdate("RestFaunaProfileUpdate");
// calculate distance from bot position to magnet point (used in all the different processes) // calculate distance from bot position to magnet point (used in all the different processes)
_magnetDist=_Bot->pos().distTo(_Bot->spawnGrp().magnetPos()); _magnetDistSq=_Bot->pos().distSqTo(_Bot->spawnGrp().magnetPos());
if (!_ArrivedInZone) if (!_ArrivedInZone)
{ {
if (_magnetDist>_Bot->spawnGrp().magnetRadiusFar()) float grpMagnetRadiusFar=_Bot->spawnGrp().magnetRadiusFar();
if (_magnetDistSq>(grpMagnetRadiusFar*grpMagnetRadiusFar))
{ {
if (!_OutOfMagnet) if (!_OutOfMagnet)
{ {
@ -656,7 +659,8 @@ void CRestFaunaProfile::updateProfile(uint ticksSinceLastUpdate)
break; break;
} }
if ( _magnetDist<=_Bot->spawnGrp().magnetRadiusNear() const float grpMagnetRadiusNear=_Bot->spawnGrp().magnetRadiusNear();
if ( _magnetDistSq<=(grpMagnetRadiusNear*grpMagnetRadiusNear)
&& _MovementMagnet->getMovementType()==CMovementMagnet::Movement_Anim) && _MovementMagnet->getMovementType()==CMovementMagnet::Movement_Anim)
{ {
_Bot->setMode(MBEHAV::REST); _Bot->setMode(MBEHAV::REST);

View file

@ -137,7 +137,7 @@ public:
protected: protected:
RYAI_MAP_CRUNCH::TAStarFlag _DenyFlags; RYAI_MAP_CRUNCH::TAStarFlag _DenyFlags;
CSpawnBotFauna* _Bot; CSpawnBotFauna* _Bot;
double _magnetDist; ///< distance from bot to his magnet at last move double _magnetDistSq; ///< square distance from bot to his magnet at last move
static CFaunaProfileFloodLogger _FloodLogger; static CFaunaProfileFloodLogger _FloodLogger;
}; };
@ -166,7 +166,7 @@ private:
CAITimer _CycleTimer; CAITimer _CycleTimer;
uint _CycleTimerBaseTime; uint _CycleTimerBaseTime;
bool _ArrivedInZone; bool _ArrivedInZone;
double _magnetDist; ///< distance from bot to his magnet at last move double _magnetDistSq; ///< square distance from bot to his magnet at last move
RYAI_MAP_CRUNCH::TAStarFlag _DenyFlags; RYAI_MAP_CRUNCH::TAStarFlag _DenyFlags;
static CFaunaProfileFloodLogger _FloodLogger; static CFaunaProfileFloodLogger _FloodLogger;
}; };
@ -196,7 +196,7 @@ private:
CAITimer _CycleTimer; CAITimer _CycleTimer;
uint _CycleTimerBaseTime; uint _CycleTimerBaseTime;
bool _ArrivedInZone; bool _ArrivedInZone;
double _magnetDist; // distance from bot to his magnet at last move double _magnetDistSq; // square distance from bot to his magnet at last move
RYAI_MAP_CRUNCH::TAStarFlag _DenyFlags; RYAI_MAP_CRUNCH::TAStarFlag _DenyFlags;
static CFaunaProfileFloodLogger _FloodLogger; static CFaunaProfileFloodLogger _FloodLogger;
}; };

View file

@ -83,14 +83,17 @@ public: // Methods.
// a few handy utility methods // a few handy utility methods
inline CAngle angleTo(const CAIPos &dest) const; inline CAngle angleTo(const CAIPos &dest) const;
inline double distTo(const CAIPos &dest) const; inline double distTo(const CAIPos &dest) const;
inline double distSqTo(const CAIPos &dest) const;
inline double quickDistTo(const CAIPos &dest) const; inline double quickDistTo(const CAIPos &dest) const;
inline CAngle angleTo(const CAIVector &dest) const; inline CAngle angleTo(const CAIVector &dest) const;
inline double distTo(const CAIVector &dest) const; inline double distTo(const CAIVector &dest) const;
inline double distSqTo(const CAIVector &dest) const;
inline double quickDistTo(const CAIVector &dest) const; inline double quickDistTo(const CAIVector &dest) const;
inline CAngle angleTo(const CAIVectorMirror &dest) const; inline CAngle angleTo(const CAIVectorMirror &dest) const;
inline double distTo(const CAIVectorMirror &dest) const; inline double distTo(const CAIVectorMirror &dest) const;
inline double distSqTo(const CAIVectorMirror &dest) const;
inline double quickDistTo(const CAIVectorMirror &dest) const; inline double quickDistTo(const CAIVectorMirror &dest) const;
protected: protected:

View file

@ -1607,6 +1607,7 @@ Then user events are triggered on the group to inform it about what happens:
- user_event_3: triggered after the player has given the mission items to the npc. - user_event_3: triggered after the player has given the mission items to the npc.
Warning: this function can only be called after the event "player_target_npc". Warning: this function can only be called after the event "player_target_npc".
Warning: only works on an R2 shard for R2 plot items.
Arguments: s(missionItems), s(missionText), c(groupToNotify) -> Arguments: s(missionItems), s(missionText), c(groupToNotify) ->
@param[in] missionItems is the list of mission items, the string format is "item1:qty1;item2:qty2;...". @param[in] missionItems is the list of mission items, the string format is "item1:qty1;item2:qty2;...".
@ -1709,38 +1710,6 @@ void receiveMissionItems_ssc_(CStateInstance* entity, CScriptStack& stack)
DEBUG_STOP; DEBUG_STOP;
return; return;
} }
// if LD use this the function outside a ring shard
if (IsRingShard)
{
// Here we destroy the item: so we do not want that a user create a scenario where we destroy
// other players precious items
static std::set<CSheetId> r2PlotItemSheetId; // :TODO: use R2Share::CRingAccess
// lazy intialisation
if (r2PlotItemSheetId.empty())
{
for (uint32 i = 0 ; i <= 184 ; ++i)
{
r2PlotItemSheetId.insert( CSheetId( NLMISC::toString("r2_plot_item_%d.sitem", i)));
}
}
// A npc give a mission to take an item given by another npc
// but the item instead of being a r2_plot_item is a normal item like system_mp or big armor
if ( r2PlotItemSheetId.find(sheetId) == r2PlotItemSheetId.end())
{
nlwarning("!!!!!!!!!!!!");
nlwarning("!!!!!!!!!!!! Someone is trying to hack us");
nlwarning("!!!!!!!!!!!!");
nlwarning("ERROR/HACK : an npc is trying to give to a player a item that is not a plot item SheetId='%s' sheetIdAsInt=%u",sheetId.toString().c_str(), sheetId.asInt());
nlwarning("His ai instanceId is %u, use log to know the sessionId and the user ", msg.InstanceId );
nlwarning("!!!!!!!!!!!!");
nlwarning("!!!!!!!!!!!!");
return ;
}
}
uint32 quantity; uint32 quantity;
NLMISC::fromString(itemAndQty[1], quantity); NLMISC::fromString(itemAndQty[1], quantity);
@ -1774,6 +1743,7 @@ Then user events are triggered on the group to inform it about what happens:
- user_event_1: triggered after the player has received the mission items from the npc. - user_event_1: triggered after the player has received the mission items from the npc.
Warning: this function can only be called after the event "player_target_npc". Warning: this function can only be called after the event "player_target_npc".
Warning: only works on an R2 shard for R2 plot items.
Arguments: s(missionItems), s(missionText), c(groupToNotify) -> Arguments: s(missionItems), s(missionText), c(groupToNotify) ->
@param[in] missionItems is the list of mission items, the string format is "item1:qty1;item2:qty2;...". @param[in] missionItems is the list of mission items, the string format is "item1:qty1;item2:qty2;...".
@ -1877,37 +1847,6 @@ void giveMissionItems_ssc_(CStateInstance* entity, CScriptStack& stack)
return; return;
} }
// if LD use this the function outside a ring shard
if (IsRingShard)
{
static std::set<CSheetId> r2PlotItemSheetId; // :TODO: use R2Share::CRingAccess
// lazy intialisation
if (r2PlotItemSheetId.empty())
{
for (uint32 i = 0 ; i <= 184 ; ++i)
{
r2PlotItemSheetId.insert( CSheetId( NLMISC::toString("r2_plot_item_%d.sitem", i)));
}
}
// A npc give a mission to give a item to another npc
// but the item instead of being a r2_plot_item is a normal item like system_mp or big armor
if ( r2PlotItemSheetId.find(sheetId) == r2PlotItemSheetId.end())
{
nlwarning("!!!!!!!!!!!!");
nlwarning("!!!!!!!!!!!! Someone is trying to hack us");
nlwarning("!!!!!!!!!!!!");
nlwarning("ERROR/HACK : an npc is trying to give to a player a item that is not a plot item SheetId='%s' sheetIdAsInt=%u",sheetId.toString().c_str(), sheetId.asInt());
nlwarning("His ai instanceId is %u, use log to know the sessionId and the user ", msg.InstanceId );
nlwarning("!!!!!!!!!!!!");
nlwarning("!!!!!!!!!!!!");
return ;
}
}
uint32 quantity; uint32 quantity;
NLMISC::fromString(itemAndQty[1], quantity); NLMISC::fromString(itemAndQty[1], quantity);
if (quantity == 0) if (quantity == 0)

View file

@ -130,6 +130,7 @@ public: // Methods.
template <class V> CAngle angleTo(const V &v) const { return CAngle(atan2((v.y()-y()).asDouble(), template <class V> CAngle angleTo(const V &v) const { return CAngle(atan2((v.y()-y()).asDouble(),
(v.x()-x()).asDouble())); } (v.x()-x()).asDouble())); }
template <class V> double distTo(const V &v) const { return (*this-v).norm(); } template <class V> double distTo(const V &v) const { return (*this-v).norm(); }
template <class V> double distSqTo(const V &v) const { return (*this-v).sqrnorm(); }
template <class V> double quickDistTo(const V &v) const { double dx=fabs((v.x()-x()).asDouble()), template <class V> double quickDistTo(const V &v) const { double dx=fabs((v.x()-x()).asDouble()),
dy=fabs((v.y()-y()).asDouble()); dy=fabs((v.y()-y()).asDouble());
return (dx>dy)? (dx+dy/2): (dy+dx/2); } return (dx>dy)? (dx+dy/2): (dy+dx/2); }

View file

@ -26,6 +26,7 @@
#include "player_manager/player_manager.h" #include "player_manager/player_manager.h"
#include "player_manager/character.h" #include "player_manager/character.h"
#include "server_share/log_item_gen.h" #include "server_share/log_item_gen.h"
#include "egs_sheets/egs_sheets.h"
using namespace std; using namespace std;
using namespace NLMISC; using namespace NLMISC;
@ -155,46 +156,58 @@ void CR2MissionItem::giveMissionItem(const NLMISC::CEntityId &eid, TSessionId se
std::vector< CGameItemPtr > itemDropToEgg; std::vector< CGameItemPtr > itemDropToEgg;
for( uint32 j = 0; j < items.size(); ++j ) for( uint32 j = 0; j < items.size(); ++j )
{ {
CGameItemPtr item = c->createItem(1, items[j].Quantity, items[j].SheetId); const CStaticItem* sitem = CSheets::getForm(items[j].SheetId);
if (sitem == NULL)
if( item != NULL )
{ {
if( c->addItemToInventory(INVENTORIES::bag, item) ) nlwarning("Attempted to give deprecated sitem sheet %s to player character %s in session %i", items[j].SheetId.toString().c_str(), c->getName().toUtf8().c_str(), sessionId.asInt());
{ }
/* // check eid is registered as character have instantiated mission item for this scenario else if (sitem->Family != ITEMFAMILY::SCROLL_R2)
TMissionItemInstanciatedOwner::iterator it = _OwnerOfInstanciatedItemFromScenario.find(scenarioId); {
if( it == _OwnerOfInstanciatedItemFromScenario.end() ) nlwarning("Attempted hack to give non-R2 item %s to player character %s in session %i", items[j].SheetId.toString().c_str(), c->getName().toUtf8().c_str(), sessionId.asInt());
{
pair< TMissionItemInstanciatedOwner::iterator, bool > ret = _OwnerOfInstanciatedItemFromScenario.insert( make_pair( scenarioId, vector< CEntityId >() ) );
if( ret.second )
{
(*ret.first).second.push_back( eid );
}
}
else
{
bool found = false;
for( uint32 i = 0; i < (*it).second.size(); ++ i )
{
if( (*it).second[i] == eid )
{
found = true;
break;
}
}
if ( ! found) { (*it).second.push_back(eid); }
}
*/
keepR2ItemAssociation(eid, scenarioId);
}
else
{
itemDropToEgg.push_back(item);
}
} }
else else
{ {
nlwarning("CR2MissionItem::giveMissionItem: can't create item %s", items[j].SheetId.toString().c_str()); CGameItemPtr item = c->createItem(1, items[j].Quantity, items[j].SheetId);
if( item != NULL )
{
if( c->addItemToInventory(INVENTORIES::bag, item) )
{
/* // check eid is registered as character have instantiated mission item for this scenario
TMissionItemInstanciatedOwner::iterator it = _OwnerOfInstanciatedItemFromScenario.find(scenarioId);
if( it == _OwnerOfInstanciatedItemFromScenario.end() )
{
pair< TMissionItemInstanciatedOwner::iterator, bool > ret = _OwnerOfInstanciatedItemFromScenario.insert( make_pair( scenarioId, vector< CEntityId >() ) );
if( ret.second )
{
(*ret.first).second.push_back( eid );
}
}
else
{
bool found = false;
for( uint32 i = 0; i < (*it).second.size(); ++ i )
{
if( (*it).second[i] == eid )
{
found = true;
break;
}
}
if ( ! found) { (*it).second.push_back(eid); }
}
*/
keepR2ItemAssociation(eid, scenarioId);
}
else
{
itemDropToEgg.push_back(item);
}
}
else
{
nlwarning("CR2MissionItem::giveMissionItem: can't create item %s", items[j].SheetId.toString().c_str());
}
} }
} }
if(itemDropToEgg.size() != 0) if(itemDropToEgg.size() != 0)
@ -273,24 +286,36 @@ void CR2MissionItem::destroyMissionItem(const NLMISC::CEntityId &eid, const std:
CSheetId itemSheetId = items[j].SheetId; CSheetId itemSheetId = items[j].SheetId;
uint32 quantity = items[j].Quantity; uint32 quantity = items[j].Quantity;
CInventoryPtr inv = c->getInventory(INVENTORIES::bag); const CStaticItem* sitem = CSheets::getForm(items[j].SheetId);
nlassert( inv != NULL ); if (sitem == NULL)
_destroyMissionItem( inv, itemSheetId, quantity );
if( quantity > 0)
{ {
for( uint32 j = INVENTORIES::pet_animal; j < INVENTORIES::max_pet_animal; ++j ) nlwarning("Attempted to take deprecated sitem sheet %s from player character %s", items[j].SheetId.toString().c_str(), c->getName().toUtf8().c_str());
{ }
inv = c->getInventory((INVENTORIES::TInventory)j); else if (sitem->Family != ITEMFAMILY::SCROLL_R2)
nlassert(inv != NULL); {
_destroyMissionItem( inv, itemSheetId, quantity ); nlwarning("Attempted hack to take non-R2 item %s from player character %s", items[j].SheetId.toString().c_str(), c->getName().toUtf8().c_str());
if(quantity == 0) }
break; else
} {
CInventoryPtr inv = c->getInventory(INVENTORIES::bag);
nlassert( inv != NULL );
_destroyMissionItem( inv, itemSheetId, quantity );
if( quantity > 0)
{
for( uint32 j = INVENTORIES::pet_animal; j < INVENTORIES::max_pet_animal; ++j )
{
inv = c->getInventory((INVENTORIES::TInventory)j);
nlassert(inv != NULL);
_destroyMissionItem( inv, itemSheetId, quantity );
if(quantity == 0)
break;
}
}
// TODO: if we can't found enough quantity of item to destroy, we need decide if we must manage that as an error
// if(quantity > 0)
// {
// }
} }
// TODO: if we can't found enough quantity of item to destroy, we need decide if we must manage that as an error
// if(quantity > 0)
// {
// }
} }
} }
} }