bool Ship::ValidateItemSpecifics(InventoryItemRef equip) const { //declaring explicitly as int...not sure if this is needed or not int groupID = m_pOperator->GetShip()->groupID(); int typeID = m_pOperator->GetShip()->typeID(); EvilNumber canFitShipGroup1 = equip->getAttribute(AttrCanFitShipGroup1); EvilNumber canFitShipGroup2 = equip->getAttribute(AttrCanFitShipGroup2); EvilNumber canFitShipGroup3 = equip->getAttribute(AttrCanFitShipGroup3); EvilNumber canFitShipGroup4 = equip->getAttribute(AttrCanFitShipGroup4); EvilNumber canFitShipType1 = equip->getAttribute(AttrCanFitShipType1); EvilNumber canFitShipType2 = equip->getAttribute(AttrCanFitShipType2); EvilNumber canFitShipType3 = equip->getAttribute(AttrCanFitShipType3); EvilNumber canFitShipType4 = equip->getAttribute(AttrCanFitShipType4); if( canFitShipGroup1 != 0 || canFitShipGroup2 != 0 || canFitShipGroup3 != 0 || canFitShipGroup4 != 0 ) if( canFitShipGroup1 != groupID && canFitShipGroup2 != groupID && canFitShipGroup3 != groupID && canFitShipGroup4 != groupID ) return false; /* if( canFitShipGroup1 != 0 ) if( canFitShipGroup1 != groupID ) return false; if( canFitShipGroup2 != 0 ) if( canFitShipGroup2 != groupID ) return false; if( canFitShipGroup3 != 0 ) if( canFitShipGroup3 != groupID ) return false; if( canFitShipGroup4 != 0 ) if( canFitShipGroup4 != groupID ) return false; */ if( canFitShipType1 != 0 || canFitShipType2 != 0 || canFitShipType3 != 0 || canFitShipType4 != 0 ) if( canFitShipType1 != typeID && canFitShipType2 != typeID && canFitShipType3 != typeID && canFitShipType4 != typeID ) return false; /* if( canFitShipType1 != 0 ) if( canFitShipType1 != typeID ) return false; if( canFitShipType2 != 0 ) if( canFitShipType2 != typeID ) return false; if( canFitShipType3 != 0 ) if( canFitShipType3 != typeID ) return false; if( canFitShipType4 != 0 ) if( canFitShipType4 != typeID ) return false; */ return true; }
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); } }
bool Ship::AlterCargoQty(InventoryItemRef item, int qtyChange) { // Make sure we actually contain this item! if (!Contains(item->itemID())) { // We don't contain it, sorry! return false; } // Calculate total volume needed. double volumeNeed = item->getAttribute(AttrVolume).get_float() * qtyChange; // Get remaining volume. double remain = GetRemainingCapacity(item->flag()); if (remain >= volumeNeed) { // We have enough space remaining, add the items. item->AlterQuantity(qtyChange); // Adjust the remaining volume. _IncreaseCargoHoldsUsedVolume(item->flag(), volumeNeed); return true; } return false; }
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; }
ModuleManager::ModuleManager(Ship *const ship) { // Create ModuleContainer object and initialize with sizes for all slot banks for this ship: m_Modules = new ModuleContainer((uint32) ship->getAttribute(AttrLowSlots).get_int(), (uint32) ship->getAttribute(AttrMedSlots).get_int(), (uint32) ship->getAttribute(AttrHiSlots).get_int(), (uint32) ship->getAttribute(AttrRigSlots).get_int(), (uint32) ship->getAttribute(AttrSubSystemSlot).get_int(), (uint32) ship->getAttribute(AttrTurretSlotsLeft).get_int(), (uint32) ship->getAttribute(AttrLauncherSlotsLeft).get_int(), this); // Store reference to the Ship object to which the ModuleManager belongs: m_Ship = ship; // Initialize the log file for this Module Manager instance std::string logsubdirectory = "ModuleManagers"; //std::string logfilename = "On_Ship_" + m_Ship->itemName(); // This method using ship's name string may NOT be path friendly as players naming ships may use path-unfriendly characters - need function to convert to path-friendly ship name string std::string logfilename = "On_Ship_" + m_Ship->itemName() + "_(" + std::string(itoa(m_Ship->itemID())) + ")"; m_pLog = new Task_Log( EVEServerConfig::files.logDir, logsubdirectory, logfilename ); m_pLog->InitializeLogging( EVEServerConfig::files.logDir, logsubdirectory, logfilename ); // Load modules, rigs and subsystems from Ship's inventory into ModuleContainer: m_pLog->Log("ModuleManager", "Loading modules..."); uint32 flagIndex; for(flagIndex=flagLowSlot0; flagIndex<=flagLowSlot7; flagIndex++) { InventoryItemRef moduleRef; InventoryItemRef chargeRef; std::vector<InventoryItemRef>::iterator cur, end; std::vector<InventoryItemRef> items; m_Ship->FindByFlag( (EVEItemFlags)flagIndex, items ); // Operator assumed to be Client * cur = items.begin(); end = items.end(); if( items.size() > 0 ) { while( (cur != end) ) { if( cur->get()->categoryID() == EVEDB::invCategories::Charge ) chargeRef = (*cur); if( cur->get()->categoryID() == EVEDB::invCategories::Module ) moduleRef = (*cur); cur++; } if( moduleRef ) { if( _fitModule( moduleRef, (EVEItemFlags)flagIndex ) ) { //_fitModule( moduleRef, (EVEItemFlags)flagIndex ); if (moduleRef->getAttribute(AttrIsOnline).get_int() == 1) Online(moduleRef->itemID()); else Offline(moduleRef->itemID()); if( chargeRef ) ((ActiveModule *)GetModule((EVEItemFlags)flagIndex))->load(chargeRef); } else { SysLog::Error( "ModuleManager::ModuleManager()", "ERROR: Cannot fit Low Slot module '%s' (id %u)", moduleRef->itemName().c_str(), moduleRef->itemID() ); throw PyException( MakeCustomError( "ERROR! Cannot fit Low Slot module '%s'", moduleRef->itemName().c_str() ) ); } } } } for(flagIndex=flagMedSlot0; flagIndex<=flagMedSlot7; flagIndex++) { InventoryItemRef moduleRef; InventoryItemRef chargeRef; std::vector<InventoryItemRef>::iterator cur, end; std::vector<InventoryItemRef> items; m_Ship->FindByFlag( (EVEItemFlags)flagIndex, items ); // Operator assumed to be Client * cur = items.begin(); end = items.end(); if( items.size() > 0 ) { while( (cur != end) ) { if( cur->get()->categoryID() == EVEDB::invCategories::Charge ) chargeRef = (*cur); if( cur->get()->categoryID() == EVEDB::invCategories::Module ) moduleRef = (*cur); cur++; } if( moduleRef ) { if( _fitModule( moduleRef, (EVEItemFlags)flagIndex ) ) { //_fitModule( moduleRef, (EVEItemFlags)flagIndex ); if (moduleRef->getAttribute(AttrIsOnline).get_int() == 1) Online(moduleRef->itemID()); else Offline(moduleRef->itemID()); if( chargeRef ) ((ActiveModule *)GetModule((EVEItemFlags)flagIndex))->load(chargeRef); } else { SysLog::Error( "ModuleManager::ModuleManager()", "ERROR: Cannot fit Med Slot module '%s' (id %u)", moduleRef->itemName().c_str(), moduleRef->itemID() ); throw PyException( MakeCustomError( "ERROR! Cannot fit Med Slot module '%s'", moduleRef->itemName().c_str() ) ); } } } } for(flagIndex=flagHiSlot0; flagIndex<=flagHiSlot7; flagIndex++) { InventoryItemRef moduleRef; InventoryItemRef chargeRef; std::vector<InventoryItemRef>::iterator cur, end; std::vector<InventoryItemRef> items; m_Ship->FindByFlag( (EVEItemFlags)flagIndex, items ); // Operator assumed to be Client * cur = items.begin(); end = items.end(); if( items.size() > 0 ) { while( (cur != end) ) { if( cur->get()->categoryID() == EVEDB::invCategories::Charge ) chargeRef = (*cur); if( cur->get()->categoryID() == EVEDB::invCategories::Module ) moduleRef = (*cur); cur++; } if( moduleRef ) { if( _fitModule( moduleRef, (EVEItemFlags)flagIndex ) ) { if (moduleRef->getAttribute(AttrIsOnline).get_int() == 1) Online(moduleRef->itemID()); else Offline(moduleRef->itemID()); if( chargeRef ) ((ActiveModule *)GetModule((EVEItemFlags)flagIndex))->load(chargeRef); } else { SysLog::Error( "ModuleManager::ModuleManager()", "ERROR: Cannot fit High Slot module '%s' (id %u)", moduleRef->itemName().c_str(), moduleRef->itemID() ); throw PyException( MakeCustomError( "ERROR! Cannot fit High Slot module '%s'", moduleRef->itemName().c_str() ) ); } } } } for(flagIndex=flagRigSlot0; flagIndex<=flagRigSlot7; flagIndex++) { InventoryItemRef itemRef; std::vector<InventoryItemRef>::iterator cur, end; std::vector<InventoryItemRef> items; m_Ship->FindByFlag( (EVEItemFlags)flagIndex, items ); // Operator assumed to be Client * cur = items.begin(); end = items.end(); if( items.size() > 0 ) { while( (cur->get()->categoryID() != EVEDB::invCategories::Module) && (cur != end) ) { cur++; } if( cur->get()->categoryID() == EVEDB::invCategories::Module ) itemRef = (*cur); if( itemRef ) { _fitModule( itemRef, (EVEItemFlags)flagIndex ); // We don't think Rigs need the Online attribute set, but keep this code here in case we do: //if( itemRef->GetAttribute(AttrIsOnline).get_int() == 1 ) // Online(itemRef->itemID()); //else // Offline(itemRef->itemID()); } } } for(flagIndex=flagSubSystem0; flagIndex<=flagSubSystem7; flagIndex++) { InventoryItemRef itemRef; std::vector<InventoryItemRef>::iterator cur, end; std::vector<InventoryItemRef> items; m_Ship->FindByFlag( (EVEItemFlags)flagIndex, items ); // Operator assumed to be Client * cur = items.begin(); end = items.end(); if( items.size() > 0 ) { while( (cur->get()->categoryID() != EVEDB::invCategories::Module) && (cur != end) ) { cur++; } if( cur->get()->categoryID() == EVEDB::invCategories::Module ) itemRef = (*cur); if( itemRef ) { _fitModule( itemRef, (EVEItemFlags)flagIndex ); // We don't think Subsystems need the Online attribute set, but keep this code here in case we do: //if( itemRef->GetAttribute(AttrIsOnline).get_int() == 1 ) // Online(itemRef->itemID()); //else // Offline(itemRef->itemID()); } } } m_pLog->Log("ModuleManager", "Module loading complete!"); }
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!" ) ); } } } }