bool InventoryItem::Merge(InventoryItemRef to_merge, int32 qty, bool notify) { if(typeID() != to_merge->typeID()) { _log(ITEM__ERROR, "%s (%u): Asked to merge with %s (%u).", itemName().c_str(), itemID(), to_merge->itemName().c_str(), to_merge->itemID()); return false; } if(locationID() != to_merge->locationID() || flag() != to_merge->flag()) { _log(ITEM__ERROR, "%s (%u) in location %u, flag %u: Asked to merge with item %u in location %u, flag %u.", itemName().c_str(), itemID(), locationID(), flag(), to_merge->itemID(), to_merge->locationID(), to_merge->flag()); return false; } if(qty == 0) qty = to_merge->quantity(); if(qty <= 0) { _log(ITEM__ERROR, "%s (%u): Asked to merge with %d units of item %u.", itemName().c_str(), itemID(), qty, to_merge->itemID()); return false; } if(!AlterQuantity(qty, notify)) { _log(ITEM__ERROR, "%s (%u): Failed to add quantity %d.", itemName().c_str(), itemID(), qty); return false; } if(qty == to_merge->quantity()) { to_merge->Delete(); } else if(!to_merge->AlterQuantity(-qty, notify)) { _log(ITEM__ERROR, "%s (%u): Failed to remove quantity %d.", to_merge->itemName().c_str(), to_merge->itemID(), qty); return false; } return true; }
void Contract::GetItemRow( InventoryItemRef item, PyPackedRow* into ) const { into->SetField( "contractID", new PyInt( contractID() ) ); into->SetField( "itemID", new PyInt( item->itemID() ) ); into->SetField( "quantity", new PyInt( item->quantity() ) ); into->SetField( "itemTypeID", new PyInt( item->typeID() ) ); into->SetField( "inCrate", new PyBool( true ) ); if( item->categoryID() == EVEDB::invCategories::Blueprint ) { BlueprintRef bp = m_itemFactory.GetBlueprint( item->itemID() ); into->SetField( "parentID", new PyInt( bp->parentBlueprintTypeID() ) ); into->SetField( "productivityLevel", new PyInt( bp->productivityLevel() ) ); into->SetField( "materialLevel", new PyInt( bp->materialLevel() ) ); into->SetField( "copy", new PyInt( bp->copy() ) ); into->SetField( "licensedProductionRunsRemaining", new PyInt( bp->licensedProductionRunsRemaining() ) ); } else { into->SetField( "parentID", new PyInt( 0 ) ); into->SetField( "productivityLevel", new PyInt( 0 ) ); into->SetField( "materialLevel", new PyInt( 0 ) ); into->SetField( "copy", new PyInt( 0 ) ); into->SetField( "licensedProductionRunsRemaining", new PyInt( 0 ) ); } if( item->HasAttribute( AttrDamage ) ) into->SetField( "damage", new PyInt( item->GetAttribute( AttrDamage ).get_int() ) ); else into->SetField( "damage", new PyInt( 0 ) ); into->SetField( "flagID", new PyInt( item->flag() ) ); }
/* * InventoryEx */ void InventoryEx::ValidateAddItem(EVEItemFlags flag, InventoryItemRef item) const { //double volume = item->quantity() * item->volume(); EvilNumber volume = EvilNumber(item->quantity()) * item->GetAttribute(AttrVolume); double capacity = GetRemainingCapacity( flag ); if( volume > capacity ) { std::map<std::string, PyRep *> args; args["available"] = new PyFloat( capacity ); args["volume"] = volume.GetPyObject(); throw PyException( MakeUserError( "NotEnoughCargoSpace", args ) ); } }
void ModuleManager::LoadCharge(InventoryItemRef chargeRef, EVEItemFlags flag) { ActiveModule * mod = (ActiveModule *)(m_Modules->GetModule(flag)); // Should not be dangrous to assume ALL modules where charges are loaded are ACTIVE modules if( mod != NULL ) { // Scenarios to handle: // + no charge loaded: check capacity >= volume of charge to add, if true, LOAD // - ELSE: if charge to load is qty > 1, calculate smallest integer qty that will EQUAL capacity, SPLIT remainder off, then LOAD! // + some charge loaded: check capacity >= volume of charge to add, if true, MERGE new charge to existing // - ELSE: if charge to load is qty > 1, calculate smallest integer qty that added to existing charge qty will EQUAL capacity, SPLIT remainder off, then LOAD! // Key facts to get: // * existing charge ref -> qty and volume/unit // * module ref -> capacity of module // * charge to add ref -> qty and volume/unit EvilNumber modCapacity = mod->getItem()->GetAttribute(AttrCapacity); EvilNumber chargeToLoadVolume = chargeRef->GetAttribute(AttrVolume); EvilNumber chargeToLoadQty = EvilNumber(chargeRef->quantity()); ///////////////////////////////////////// // chargeRef->Split(); // chargeRef->Merge(); // mod->Load(chargeRef); // chargeRef->Move(m_Ship->itemID(), flag); // used to be (m_pOperator->GetLocationID(), flag) ///////////////////////////////////////// //m_Ship->GetOperator()->Client()->MoveItem(chargeRef->itemID(), m_Ship->itemID(), flag); if( mod->isLoaded() ) { // Module is loaded, let's check available capacity: InventoryItemRef loadedChargeRef = mod->getLoadedChargeRef(); EvilNumber loadedChargeVolume = loadedChargeRef->GetAttribute(AttrVolume); EvilNumber loadedChargeQty = EvilNumber(loadedChargeRef->quantity()); modCapacity -= (loadedChargeVolume * loadedChargeQty); // Calculate remaining capacity if( chargeRef->typeID() != loadedChargeRef->typeID() ) { // Different charge type is being swapped into this module, so unload what's loaded if( IsStation(m_Ship->GetOperator()->GetLocationID()) ) loadedChargeRef->Move(m_Ship->locationID(), flagHangar); else { m_Ship->ValidateAddItem(flagCargoHold,loadedChargeRef); loadedChargeRef->Move(m_Ship->itemID(), flagCargoHold); } mod->unload(); // Loading of charge will be performed below } else { if( modCapacity > chargeToLoadVolume ) { // Great! We can load at least one, let's top off the loaded charges: uint32 quantityWeCanLoad = floor((modCapacity / chargeToLoadVolume).get_float()); if( quantityWeCanLoad > 0 ) { if( quantityWeCanLoad < chargeToLoadQty.get_int() ) { // Split chargeRef to qty 'quantityWeCanLoad' // Merge new smaller qty 'quantityWeCanLoad' with loadedChargeRef // Load this merged charge Ref into module InventoryItemRef loadableChargeQtyRef = chargeRef->Split( quantityWeCanLoad ); loadableChargeQtyRef->ChangeOwner( chargeRef->ownerID() ); loadedChargeRef->Merge( loadableChargeQtyRef ); mod->load( loadedChargeRef ); loadedChargeRef->Move(m_Ship->itemID(), flag); // used to be (m_pOperator->GetLocationID(), flag) } else { // Merge chargeRef with loadedChargeRef // Load this merged charge Ref into module loadedChargeRef->Merge( chargeRef ); mod->load( loadedChargeRef ); loadedChargeRef->Move(m_Ship->itemID(), flag); // used to be (m_pOperator->GetLocationID(), flag) } } else throw PyException( MakeCustomError( "Cannot load even one unit of this charge!" ) ); } else { throw PyException( MakeCustomError( "Charge is full!" ) ); } } } // Refresh ammo capacity of module in case it was modified in previous code block ahead of a load action: modCapacity = mod->getItem()->GetAttribute(AttrCapacity); // Load charge supplied if this module was either never loaded, or just unloaded from a different type right above: if( !(mod->isLoaded()) ) { // Module is not loaded at all, let's check total volume of charge to load against available capacity: if( modCapacity >= (chargeToLoadVolume * chargeToLoadQty) ) { // We can insert entire stack of chargeRef into module // Load chargeRef as-is into module mod->load( chargeRef ); chargeRef->Move(m_Ship->itemID(), flag); // used to be (m_pOperator->GetLocationID(), flag) } else { // We need to split off only as many charge units as can fit into this module // Split chargeRef uint32 quantityWeCanLoad = floor((modCapacity / chargeToLoadVolume).get_float()); if( quantityWeCanLoad > 0 ) { // Split chargeRef to qty 'quantityWeCanLoad' // Merge new smaller qty 'quantityWeCanLoad' with loadedChargeRef // Load this merged charge Ref into module InventoryItemRef loadableChargeQtyRef = chargeRef->Split( quantityWeCanLoad ); loadableChargeQtyRef->ChangeOwner( chargeRef->ownerID() ); mod->load( loadableChargeQtyRef ); loadableChargeQtyRef->Move(m_Ship->itemID(), flag); // used to be (m_pOperator->GetLocationID(), flag) } else throw PyException( MakeCustomError( "Cannot load even one unit of this charge!" ) ); } } } }
void Ship::RemoveItem(InventoryItemRef item, uint32 inventoryID, EVEItemFlags flag) { // If item IS a module and it's being removed from a slot: if( (item->categoryID() == EVEDB::invCategories::Module) && ((item->flag() >= flagLowSlot0) && (item->flag() <= flagHiSlot7)) ) { m_pOperator->GetShip()->Deactivate( item->itemID(), "online" ); // m_pOperator->GetShip()->Set_mass( m_pOperator->GetShip()->mass() - item->massAddition() ); //m_pOperator->GetShip()->SetAttribute(AttrMass, m_pOperator->GetShip()->GetAttribute(AttrMass) - item->GetAttribute(AttrMassAddition) ); m_pOperator->GetShip()->UnloadModule( item->itemID() ); } // If item IS a rig and it's being removed from a slot: if( (item->categoryID() == EVEDB::invCategories::Module) && ((item->flag() >= flagRigSlot0) && (item->flag() <= flagRigSlot7)) ) { // Don't know what to do when removing a Rig... yet ;) } // If item IS a rig and it's being removed from a slot: if( (item->categoryID() == EVEDB::invCategories::Subsystem) && ((item->flag() >= flagSubSystem0) && (item->flag() <= flagSubSystem7)) ) { // Don't know what to do when removing a Subsystem... yet ;) } // if item being removed IS a charge, it needs to be removed via Module Manager so modules know charge is removed, // BUT, only if it is loaded into a module in one of the 3 slot banks, so we also check its flag value: if( (item->categoryID() == EVEDB::invCategories::Charge) && ((item->flag() >= flagLowSlot0) && (item->flag() <= flagHiSlot7)) ) { m_ModuleManager->UnloadCharge(item->flag()); } if( item->flag() == flag ) // Item's already been moved, let's return return; // Move New item to its new location: if( !( ((item->flag() >= flagLowSlot0) && (item->flag() <= flagHiSlot7)) || ((item->flag() >= flagRigSlot0) && (item->flag() <= flagRigSlot7)) || ((item->flag() >= flagSubSystem0) && (item->flag() <= flagSubSystem7)) ) ) { _DecreaseCargoHoldsUsedVolume(item->flag(), (item->getAttribute(AttrVolume).get_float() * item->quantity())); m_pOperator->MoveItem(item->itemID(), inventoryID, flag); } else { m_pOperator->MoveItem(item->itemID(), inventoryID, flag); } }
uint32 Ship::AddItem(EVEItemFlags flag, InventoryItemRef item) { ValidateAddItem( flag, item ); //it's a new module, make sure it's state starts at offline so that it is added correctly if( item->categoryID() == EVEDB::invCategories::Module ) item->PutOffline(); switch( item->categoryID() ) { case EVEDB::invCategories::Charge: { m_ModuleManager->LoadCharge(item, flag); InventoryItemRef loadedChargeOnModule = m_ModuleManager->GetLoadedChargeOnModule(flag); if( loadedChargeOnModule ) { return loadedChargeOnModule->itemID(); } else return 0; } break; case EVEDB::invCategories::Module: if( m_ModuleManager->FitModule(item, flag) ) item->Move(itemID(), flag); break; // The default case handles ANY other items added to ship and assumes they go into one of the valid cargo holds on this ship: default: //Log::Error( "Ship::AddItem(flag,item)", "ERROR! Function called with item '%s' (id: %u) of category neither Charge nor Module!", item->itemName().c_str(), item->itemID() ); _IncreaseCargoHoldsUsedVolume(item->flag(), (item->getAttribute(AttrVolume).get_float() * item->quantity())); item->Move(itemID(), flag); break; } return 0; }
bool Ship::ValidateAddItem(EVEItemFlags flag, InventoryItemRef item) const { CharacterRef character = m_pOperator->GetChar(); if( flag == flagDroneBay ) { if (item->categoryID() != EVEDB::invCategories::Drone) { //Can only put drones in drone bay throw PyException(MakeUserError("ItemCannotBeInDroneBay")); } } else if( flag == flagShipHangar ) { if (m_pOperator->GetShip()->getAttribute(AttrHasShipMaintenanceBay) != 0) { // We have no ship maintenance bay throw PyException(MakeCustomError("%s has no ship maintenance bay.", item->itemName().c_str())); } if (item->categoryID() != EVEDB::invCategories::Ship) { // Only ships may be put here throw PyException(MakeCustomError("Only ships may be placed into ship maintenance bay.")); } } else if( flag == flagHangar ) { if (m_pOperator->GetShip()->getAttribute(AttrHasCorporateHangars) != 0) { // We have no corporate hangars throw PyException(MakeCustomError("%s has no corporate hangars.", item->itemName().c_str())); } } else if( (flag >= flagLowSlot0) && (flag <= flagHiSlot7) ) { if (m_pOperator->IsClient()) { // SKIP THIS SKILL CHECK if Operator is NOT Client * if (!character->canUse(item)) { throw PyException(MakeCustomError("You do not have the required skills to fit this \n%s", item->itemName().c_str())); } } if (!ValidateItemSpecifics(item)) { throw PyException(MakeCustomError("Your ship cannot equip this module")); } if(item->categoryID() == EVEDB::invCategories::Charge) { if( m_ModuleManager->GetModule(flag) != NULL ) { InventoryItemRef module; module = m_ModuleManager->GetModule(flag)->getItem(); if (module->getAttribute(AttrChargeSize) != item->getAttribute(AttrChargeSize)) throw PyException( MakeCustomError( "The charge is not the correct size for this module." ) ); if (module->getAttribute(AttrChargeGroup1) != item->groupID()) throw PyException( MakeCustomError( "Incorrect charge type for this module.") ); // NOTE: Module Manager will check for actual room to load charges and make stack splits, or reject loading altogether } else { throw PyException(MakeCustomError("Module at flag '%u' does not exist!", flag)); } } else { if (m_ModuleManager->IsSlotOccupied(flag)) { throw PyException(MakeUserError("SlotAlreadyOccupied")); } } return true; } else if( (flag >= flagRigSlot0) && (flag <= flagRigSlot7) ) { if (m_pOperator->IsClient()) { // SKIP THIS SKILL CHECK if Operator is NOT Client * if (!character->canUse(item)) { throw PyException(MakeCustomError("You do not have the required skills to fit this \n%s", item->itemName().c_str())); } } if (m_pOperator->GetShip()->getAttribute(AttrRigSize) != item->getAttribute(AttrRigSize)) { throw PyException(MakeCustomError("Your ship cannot fit this size module")); } if (m_pOperator->GetShip()->getAttribute(AttrUpgradeLoad) + item->getAttribute(AttrUpgradeCost) > m_pOperator->GetShip()->getAttribute(AttrUpgradeCapacity)) { throw PyException(MakeCustomError("Your ship cannot handle the extra calibration")); } return true; } else if( (flag >= flagSubSystem0) && (flag <= flagSubSystem7) ) { if (m_pOperator->IsClient()) { // SKIP THIS SKILL CHECK if Operator is NOT Client * if (!character->canUse(item)) { throw PyException(MakeCustomError("You do not have the required skills to fit this \n%s", item->itemName().c_str())); } } return true; } // Handle any other flag, legal or not by virtue of GetRemainingVolumeByFlag() and GetCapacity() that handle supported capacity types: // (unsupported or illegal flags report capacity of 0.0, so are automatically rejected) double capacityRemaining(0.0); capacityRemaining = GetRemainingVolumeByFlag(flag); // Check for sufficient capacity. if ((capacityRemaining < (item->getAttribute(AttrVolume).get_float() * (double) item->quantity()))) { throw PyException(MakeCustomError("Not enough cargo space!<br><br>flag = %u", (uint32) flag)); return false; } return true; }