void ModuleManager::UnfitModule(uint32 itemID) { GenericModule * mod = m_Modules->GetModule(itemID); if( mod != NULL ) { if( mod->isLoaded() ) { InventoryItemRef loadedChargeRef = mod->getLoadedChargeRef(); if( IsStation(m_Ship->locationID()) ) loadedChargeRef->Move(m_Ship->locationID(), flagHangar); // used to be (m_pOperator->GetLocationID(), flag) else { m_Ship->ValidateAddItem(flagCargoHold,loadedChargeRef); //if( m_Ship->ValidateAddItem(flagCargoHold,loadedChargeRef) ) //{ loadedChargeRef->Move(m_Ship->itemID(), flagCargoHold); // used to be (m_pOperator->GetLocationID(), flag) mod->unload(); //} //else // throw PyException( MakeCustomError( "Not enough cargo space!") ); } } mod->offline(); m_Modules->RemoveModule(itemID); } }
PyResult Command_createitem( Client* who, CommandDB* db, PyServiceMgr* services, const Seperator& args ) { if( args.argCount() < 2 ) { throw PyException( MakeCustomError("Correct Usage: /create [typeID]") ); } //basically, a copy/paste from Command_create. The client seems to call this multiple times, //each time it creates an item if( !args.isNumber( 1 ) ) throw PyException( MakeCustomError( "Argument 1 must be type ID." ) ); const uint32 typeID = atoi( args.arg( 1 ).c_str() ); uint32 qty = 1; if( 2 < args.argCount() ) { if( args.isNumber( 2 ) ) qty = atoi( args.arg( 2 ).c_str() ); } sLog.Log("command message", "Create %s %u times", args.arg( 1 ).c_str(), qty ); //create into their cargo hold unless they are docked in a station, //then stick it in their hangar instead. uint32 locationID; EVEItemFlags flag; if( who->IsInSpace() ) { locationID = who->GetShipID(); flag = flagCargoHold; } else { locationID = who->GetStationID(); flag = flagHangar; } ItemData idata( typeID, who->GetCharacterID(), 0, //temp location flag, qty ); InventoryItemRef i = services->item_factory.SpawnItem( idata ); if( !i ) throw PyException( MakeCustomError( "Unable to create item of type %s.", args.arg( 1 ).c_str() ) ); //Move to location i->Move( locationID, flag, true ); return new PyString( "Creation successful." ); }
void 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::Charge ) item->PutOffline(); item->Move(m_pOperator->GetLocationID(), flag); //TODO - check this m_ModuleManager->FitModule(item); }
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; }
void 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::Charge ) item->PutOffline(); // TODO: Somehow, if this returns FALSE, the item->Move() above has to be "undone"... can we do the move AFTER attempting to fit? // what if we pass the flag into FitModule().... then if it returns true, the item->Move() can be called if( m_ModuleManager->FitModule(item, flag) ) item->Move(m_pOperator->GetLocationID(), flag); //TODO - check this }
void Contract::Delete() { // Return the items to the hangar std::map<uint32, ContractGetItemsRef>::iterator cur, end; cur = items().begin(); end = items().end(); for(; cur != end; cur++) { InventoryItemRef item = m_itemFactory.GetItem( cur->second->m_itemID ); item->Move( startStationID(), flagHangar, true ); item->ChangeOwner( issuerID(), true ); } // take ourself out of the DB m_factory.db().DeleteContract( contractID() ); // Delete ourselves from factory cache m_factory.DeleteContract( contractID() ); }
InventoryItemRef InventoryItem::Split(int32 qty_to_take, bool notify) { if(qty_to_take <= 0) { _log(ITEM__ERROR, "%s (%u): Asked to split into a chunk of %d", itemName().c_str(), itemID(), qty_to_take); return InventoryItemRef(); } if(!AlterQuantity(-qty_to_take, notify)) { _log(ITEM__ERROR, "%s (%u): Failed to remove quantity %d during split.", itemName().c_str(), itemID(), qty_to_take); return InventoryItemRef(); } ItemData idata( typeID(), ownerID(), (notify ? 1 : locationID()), //temp location to cause the spawn via update flag(), qty_to_take ); InventoryItemRef res = m_factory.SpawnItem(idata); if(notify) res->Move( locationID(), flag() ); return( res ); }
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!" ) ); } } } }
PyResult ContractMgrService::Handle_CreateContract( PyCallArgs& call ) { Call_CreateContract info; PyList* requestItemTypeList = new PyList; PyList* itemList = new PyList; uint32 flag = 0; bool forCorp = false; double volume = 0; uint32 maxCharContracts = 0; if( call.byname.find( "forCorp" ) != call.byname.end() ) { forCorp = call.byname.find( "forCorp" )->second->AsBool()->value(); } // Let's see the players limit of contracts CharacterRef ch = call.client->GetChar(); if( forCorp ) { if( ch->HasSkill( 25233 ) ) { SkillRef skill = ch->GetSkill( 25233 ); uint32 skillLevel = skill->GetAttribute( 280 ).get_int(); maxCharContracts = ( 10 * skillLevel ) + 10; } else { maxCharContracts = 10; } } else { if( ch->HasSkill( 25235 ) ) { SkillRef skill = ch->GetSkill( 25235 ); uint32 skillLevel = skill->GetAttribute( 280 ).get_int(); maxCharContracts = ( 4 * skillLevel ) + 1; } else { maxCharContracts = 1; } uint32 numOutstandingContractsNonCorp = 0; uint32 numOutstandingContractsForCorp = 0; std::map<uint32, ContractRef>::const_iterator cur, end; std::map<uint32, ContractRef> contracts = m_contractManager->GetContractList(); cur = contracts.begin(); end = contracts.end(); for(; cur != end; cur++ ) { ContractRef contract = cur->second; if( contract->issuerID() == call.client->GetCharacterID() ) { if( contract->forCorp() ) numOutstandingContractsForCorp += 1; else numOutstandingContractsNonCorp += 1; } } if( ( forCorp ) && ( numOutstandingContractsForCorp >= maxCharContracts ) ) { call.client->SendInfoModalMsg( "Your Corporation Contracting skill level only allows you to create %d public contracts for your corp/alliance", maxCharContracts ); return new PyBool( false ); } if( ( !forCorp ) && ( numOutstandingContractsNonCorp >= maxCharContracts ) ) { call.client->SendInfoModalMsg( "Your Contracting skill level only allows you to create %d public contracts", maxCharContracts ); return new PyBool( false ); } } if( !info.Decode( &call.tuple ) ) { codelog(SERVICE__ERROR, "%s: Bad arguments to CreateContract in contractMgr", call.client->GetCharacterName() ); return NULL; } if( call.byname.find( "requestItemTypeList" ) != call.byname.end() ) { requestItemTypeList = call.byname.find( "requestItemTypeList" )->second->AsList(); } if( call.byname.find( "flag" ) != call.byname.end() ) { flag = call.byname.find( "flag" )->second->AsInt()->value(); } if( call.byname.find( "itemList" ) != call.byname.end() ) { itemList = call.byname.find( "itemList" )->second->AsList(); } if( info.endStationID == 0 )info.endStationID = info.startStationID; ContractData* cData = new ContractData( call.client->GetCharacterID(), call.client->GetCorporationID(), info.type, info.avail, info.assigneeID, info.expiretime, info.expiretime, info.startStationID, info.endStationID, call.client->GetSystemID(), call.client->GetSystemID(), call.client->GetRegionID(), call.client->GetRegionID(), info.price, info.reward, info.collateral, info.title, info.description, forCorp, conStatusOutstanding, false, 0, Win32TimeNow(), Win32TimeNow() + ( info.duration * Win32Time_Day ), Win32TimeNow(), Win32TimeNow(), 0, false, 0, 0, 0 ); std::map<uint32, ContractRequestItemRef> requestItems; std::map<uint32, ContractGetItemsRef> items; uint32 itemID = 0; uint32 typeID = 0; for( size_t i = 0; i < itemList->size(); i ++ ) { if( itemList->IsList() ) { if( itemList->GetItem( i )->AsList()->GetItem( 0 )->IsInt() ) itemID = itemList->GetItem( i )->AsList()->GetItem( 0 )->AsInt()->value(); else{ sLog.Error( "ContractMgrService", "Wrong list args" ); break; } } InventoryItemRef item = m_manager->item_factory.GetItem( itemID ); if( item == NULL ) { sLog.Error( "ContractMgrService", "GetItem returned NULL" ); break; } item->Move( call.client->GetStationID(), flagBriefcase, true ); item->ChangeOwner( 1, true ); items.insert( std::make_pair( itemID, ContractGetItemsRef( new ContractGetItems( itemID, itemList->GetItem( i )->AsList()->GetItem( 1 )->AsInt()->value() ) ) ) ); } if( cData->m_type == conTypeItemExchange ) { for( size_t i = 0; i < requestItemTypeList->size(); i ++ ) { if( itemList->IsList() ) { if( requestItemTypeList->GetItem( i )->AsList()->GetItem( 0 )->IsInt() ) typeID = requestItemTypeList->GetItem( i )->AsList()->GetItem( 0 )->AsInt()->value(); else{ sLog.Error( "ContractMgrService", "Wrong list args" ); break; } } requestItems.insert( std::make_pair( itemID, ContractRequestItemRef( new ContractRequestItem(itemID, requestItemTypeList->GetItem( i )->AsList()->GetItem( 1 )->AsInt()->value() ) ) ) ); } } uint32 contractID = 0; sLog.Debug( "ContractMgrService", "Creating contract..." ); ContractRef _contract = ContractRef( new Contract( contractID, *cData, requestItems, items, m_manager->item_factory, *m_contractManager ) ); contractID = m_contractManager->CreateContract( _contract ); sLog.Debug( "ContractMgrService", "Contract created" ); return new PyInt( contractID ); }
PyResult RamProxyService::Handle_CompleteJob(PyCallArgs &call) { Call_CompleteJob args; if(!args.Decode(&call.tuple)) { _log(CLIENT__ERROR, "Failed to decode args."); return NULL; } _VerifyCompleteJob(args, call.client); // hundreds of variables to allocate ... maybe we can make struct for GetJobProperties and InstallJob? uint32 installedItemID, ownerID, runs, licensedProductionRuns; EVEItemFlags outputFlag; EVERamActivity activity; if(!m_db.GetJobProperties(args.jobID, installedItemID, ownerID, outputFlag, runs, licensedProductionRuns, activity)) return NULL; // return item InventoryItemRef installedItem = m_manager->item_factory.GetItem( installedItemID ); if( !installedItem ) return NULL; installedItem->Move( installedItem->locationID(), outputFlag ); std::vector<RequiredItem> reqItems; if( !m_db.GetRequiredItems( installedItem->typeID(), activity, reqItems ) ) return NULL; // return materials which weren't completely consumed std::vector<RequiredItem>::iterator cur, end; cur = reqItems.begin(); end = reqItems.end(); for(; cur != end; cur++) { if(!cur->isSkill && cur->damagePerJob != 1.0) { uint32 quantity = static_cast<uint32>(cur->quantity * runs * (1.0 - cur->damagePerJob)); if(quantity == 0) continue; ItemData idata( cur->typeID, ownerID, 0, //temp location outputFlag, quantity ); InventoryItemRef item = m_manager->item_factory.SpawnItem( idata ); if( !item ) return NULL; item->Move(args.containerID, outputFlag); } } // if not cancelled, realize result of activity if(!args.cancel) { switch(activity) { /* * Manufacturing */ case ramActivityManufacturing: { BlueprintRef bp = BlueprintRef::StaticCast( installedItem ); ItemData idata( bp->productTypeID(), ownerID, 0, // temp location outputFlag, bp->productType().portionSize() * runs ); InventoryItemRef item = m_manager->item_factory.SpawnItem( idata ); if( !item ) return NULL; item->Move(args.containerID, outputFlag); } break; /* * Time productivity research */ case ramActivityResearchingTimeProductivity: { BlueprintRef bp = BlueprintRef::StaticCast( installedItem ); bp->AlterProductivityLevel( runs ); } break; /* * Material productivity research */ case ramActivityResearchingMaterialProductivity: { BlueprintRef bp = BlueprintRef::StaticCast( installedItem ); bp->AlterMaterialLevel( runs) ; } break; /* * Copying */ case ramActivityCopying: { BlueprintRef bp = BlueprintRef::StaticCast( installedItem ); ItemData idata( installedItem->typeID(), ownerID, 0, //temp location outputFlag, runs ); BlueprintData bdata( true, bp->materialLevel(), bp->productivityLevel(), licensedProductionRuns ); BlueprintRef copy = m_manager->item_factory.SpawnBlueprint( idata, bdata ); if( !copy ) return NULL; copy->Move(args.containerID, outputFlag); } break; /* * The rest is unsupported */ case ramActivityResearchingTechnology: case ramActivityDuplicating: case ramActivityReverseEngineering: case ramActivityInvention: default: { _log(SERVICE__ERROR, "Activity %u is currently unsupported.", activity); } break; } } // regardless on success of this, we will return NULL, so there's no condition here m_db.CompleteJob(args.jobID, args.cancel ? ramCompletedStatusAbort : ramCompletedStatusDelivered); return NULL; }
PyResult RamProxyService::Handle_InstallJob(PyCallArgs &call) { Call_InstallJob args; if(!args.Decode(&call.tuple)) { _log(SERVICE__ERROR, "Failed to decode args."); return NULL; } // load installed item InventoryItemRef installedItem = m_manager->item_factory.GetItem( args.installedItemID ); if( !installedItem ) return NULL; // if output flag not set, put it where it was if(args.flagOutput == flagAutoFit) args.flagOutput = installedItem->flag(); // decode path to BOM location PathElement pathBomLocation; if( !pathBomLocation.Decode( args.bomPath->GetItem(0) ) ) { _log(SERVICE__ERROR, "Failed to decode BOM location."); return NULL; } // verify call _VerifyInstallJob_Call( args, (InventoryItemRef)installedItem, pathBomLocation, call.client ); // this calculates some useful multipliers ... Rsp_InstallJob is used as container ... Rsp_InstallJob rsp; if(!_Calculate(args, (InventoryItemRef)installedItem, call.client, rsp)) return NULL; // I understand sent maxJobStartTime as a limit, so this checks whether it's in limit if(rsp.maxJobStartTime > call.byname["maxJobStartTime"]->AsInt()->value()) throw(PyException(MakeUserError("RamCannotGuaranteeStartTime"))); // query required items for activity std::vector<RequiredItem> reqItems; if(!m_db.GetRequiredItems(installedItem->typeID(), (EVERamActivity)args.activityID, reqItems)) return NULL; // if 'quoteOnly' is 1 -> send quote, if 0 -> install job if(call.byname["quoteOnly"]->AsInt()->value()) { _EncodeBillOfMaterials(reqItems, rsp.materialMultiplier, rsp.charMaterialMultiplier, args.runs, rsp.bom); _EncodeMissingMaterials(reqItems, pathBomLocation, call.client, rsp.materialMultiplier, rsp.charMaterialMultiplier, args.runs, rsp.missingMaterials); return rsp.Encode(); } else { // verify install _VerifyInstallJob_Install(rsp, pathBomLocation, reqItems, args.runs, call.client); // now we are sure everything from the client side is right, we can start it ... // calculate proper start time uint64 beginProductionTime = Win32TimeNow(); if(beginProductionTime < (uint32)rsp.maxJobStartTime) beginProductionTime = rsp.maxJobStartTime; // register our job if( !m_db.InstallJob( args.isCorpJob ? call.client->GetCorporationID() : call.client->GetCharacterID(), call.client->GetCharacterID(), args.installationAssemblyLineID, installedItem->itemID(), beginProductionTime, beginProductionTime + uint64(rsp.productionTime) * Win32Time_Second, args.description.c_str(), args.runs, (EVEItemFlags)args.flagOutput, pathBomLocation.locationID, args.licensedProductionRuns ) ) { return NULL; } // do some activity-specific actions switch(args.activityID) { case ramActivityManufacturing: { // decrease licensed production runs BlueprintRef bp = BlueprintRef::StaticCast( installedItem ); if(!bp->infinite()) bp->AlterLicensedProductionRunsRemaining(-1); } } // pay for assembly lines, move the item away call.client->AddBalance(-rsp.cost); installedItem->Move( installedItem->locationID(), flagFactoryBlueprint ); // query all items contained in "Bill of Materials" location std::vector<InventoryItemRef> items; _GetBOMItems( pathBomLocation, items ); std::vector<RequiredItem>::iterator cur, end; cur = reqItems.begin(); end = reqItems.end(); for(; cur != end; cur++) { if(cur->isSkill) continue; // not interested // calculate needed quantity uint32 qtyNeeded = static_cast<uint32>(ceil(cur->quantity * rsp.materialMultiplier * args.runs)); if(cur->damagePerJob == 1.0) qtyNeeded = static_cast<uint32>(ceil(qtyNeeded * rsp.charMaterialMultiplier)); // skill multiplier is applied only on fully consumed materials std::vector<InventoryItemRef>::iterator curi, endi; curi = items.begin(); endi = items.end(); // consume required materials for(; curi != endi; curi++) { if((*curi)->typeID() == cur->typeID && (*curi)->ownerID() == call.client->GetCharacterID()) { if(qtyNeeded >= (*curi)->quantity()) { qtyNeeded -= (*curi)->quantity(); (*curi)->Delete(); } else { (*curi)->AlterQuantity(-(int32)qtyNeeded); break; // we are done, stop searching } } } } return NULL; } }