void RamProxyService::_VerifyInstallJob_Call(const Call_InstallJob &args, InventoryItemRef installedItem, const PathElement &bomLocation, Client *const c) { // ACTIVITY CHECK // *************** const ItemType *productType; switch(args.activityID) { /* * Manufacturing */ case ramActivityManufacturing: { if(installedItem->categoryID() != EVEDB::invCategories::Blueprint) throw(PyException(MakeUserError("RamActivityRequiresABlueprint"))); BlueprintRef bp = BlueprintRef::StaticCast( installedItem ); if(!bp->infinite() && (bp->licensedProductionRunsRemaining() - args.runs) < 0) throw(PyException(MakeUserError("RamTooManyProductionRuns"))); productType = &bp->productType(); break; } /* * Time/Material Research */ case ramActivityResearchingMaterialProductivity: case ramActivityResearchingTimeProductivity: { if(installedItem->categoryID() != EVEDB::invCategories::Blueprint) throw(PyException(MakeUserError("RamActivityRequiresABlueprint"))); BlueprintRef bp = BlueprintRef::StaticCast( installedItem ); if(bp->copy()) throw(PyException(MakeUserError("RamCannotResearchABlueprintCopy"))); productType = &bp->type(); break; } /* * Copying */ case ramActivityCopying: { if(installedItem->categoryID() != EVEDB::invCategories::Blueprint) throw(PyException(MakeUserError("RamActivityRequiresABlueprint"))); BlueprintRef bp = BlueprintRef::StaticCast( installedItem ); if(bp->copy()) throw(PyException(MakeUserError("RamCannotCopyABlueprintCopy"))); productType = &bp->type(); break; } /* * The rest */ case ramActivityResearchingTechnology: case ramActivityDuplicating: case ramActivityReverseEngineering: case ramActivityInvention: /* { if(installedItem->categoryID() != EVEDB::invCategories::Blueprint) throw(PyException(MakeUserError("RamActivityRequiresABlueprint"))); Blueprint *bp = (Blueprint *)installedItem; if(!bp->copy()) throw(PyException(MakeUserError("RamCannotInventABlueprintOriginal"))); uint32 productTypeID = m_db.GetTech2Blueprint(installedItem->typeID()); if(productTypeID == NULL) throw(PyException(MakeUserError("RamInventionNoOutput"))); productType = m_manager->item_factory.type(productTypeID); break; } */ default: { // not supported throw(PyException(MakeUserError("RamActivityInvalid"))); //throw(PyException(MakeUserError("RamNoKnownOutputType"))); } } if(!m_db.IsProducableBy(args.installationAssemblyLineID, productType->groupID())) throw(PyException(MakeUserError("RamBadEndProductForActivity"))); // JOBS CHECK // *********** if(args.activityID == ramActivityManufacturing) { uint32 jobCount = m_db.CountManufacturingJobs(c->GetCharacterID()); if(c->GetChar()->GetAttribute(AttrManufactureSlotLimit).get_int() <= jobCount) { std::map<std::string, PyRep *> exceptArgs; exceptArgs["current"] = new PyInt(jobCount); exceptArgs["max"] = c->GetChar()->GetAttribute(AttrManufactureSlotLimit).GetPyObject(); throw(PyException(MakeUserError("MaxFactorySlotUsageReached", exceptArgs))); } } else { uint32 jobCount = m_db.CountResearchJobs(c->GetCharacterID()); if(c->GetChar()->GetAttribute(AttrMaxLaborotorySlots).get_int() <= jobCount) { std::map<std::string, PyRep *> exceptArgs; exceptArgs["current"] = new PyInt(jobCount); exceptArgs["max"] = c->GetChar()->GetAttribute(AttrMaxLaborotorySlots).GetPyObject(); throw(PyException(MakeUserError("MaxResearchFacilitySlotUsageReached", exceptArgs))); } } // INSTALLATION CHECK // ******************* uint32 regionID = m_db.GetRegionOfContainer(args.installationContainerID); if(regionID == 0) throw(PyException(MakeUserError("RamIsNotAnInstallation"))); if(c->GetRegionID() != regionID) throw(PyException(MakeUserError("RamRangeLimitationRegion"))); // RamStructureNotInSpace // RamStructureNotIsSolarsystem // RamRangeLimitation // RamRangeLimitationJumps // RamRangeLimitationJumpsNoSkill // ASSEMBLY LINE CHECK // ********************* uint32 ownerID; double minCharSec, maxCharSec; EVERamRestrictionMask restrictionMask; EVERamActivity activity; // get properties if(!m_db.GetAssemblyLineVerifyProperties(args.installationAssemblyLineID, ownerID, minCharSec, maxCharSec, restrictionMask, activity)) throw(PyException(MakeUserError("RamInstallationHasNoDefaultContent"))); // check validity of activity if(activity < ramActivityManufacturing || activity > ramActivityInvention) throw(PyException(MakeUserError("RamAssemblyLineHasNoActivity"))); // check security rating if required if((restrictionMask & ramRestrictBySecurity) == ramRestrictBySecurity) { if(minCharSec > c->GetSecurityRating()) throw(PyException(MakeUserError("RamAccessDeniedSecStatusTooLow"))); if(maxCharSec < c->GetSecurityRating()) throw(PyException(MakeUserError("RamAccessDeniedSecStatusTooHigh"))); // RamAccessDeniedCorpSecStatusTooHigh // RamAccessDeniedCorpSecStatusTooLow } // check standing if required if((restrictionMask & ramRestrictByStanding) == ramRestrictByStanding) { // RamAccessDeniedCorpStandingTooLow // RamAccessDeniedStandingTooLow } if((restrictionMask & ramRestrictByAlliance) == ramRestrictByAlliance) { // if(...) throw(PyException(MakeUserError("RamAccessDeniedWrongAlliance"))); } else if((restrictionMask & ramRestrictByCorp) == ramRestrictByCorp) { if(ownerID != c->GetCorporationID()) throw(PyException(MakeUserError("RamAccessDeniedWrongCorp"))); } if(args.isCorpJob) { if((c->GetCorpRole() & corpRoleFactoryManager) != corpRoleFactoryManager) throw(PyException(MakeUserError("RamCannotInstallForCorpByRoleFactoryManager"))); if(args.activityID == ramActivityManufacturing) { if((c->GetCorpRole() & corpRoleCanRentFactorySlot) != corpRoleCanRentFactorySlot) throw(PyException(MakeUserError("RamCannotInstallForCorpByRole"))); } else { if((c->GetCorpRole() & corpRoleCanRentResearchSlot) != corpRoleCanRentResearchSlot) throw(PyException(MakeUserError("RamCannotInstallForCorpByRole"))); } } // INSTALLED ITEM CHECK // ********************* // ownership if(args.isCorpJob) { if(installedItem->ownerID() != c->GetCorporationID()) throw(PyException(MakeUserError("RamCannotInstallItemForAnotherCorp"))); } else { if(installedItem->ownerID() != c->GetCharacterID()) throw(PyException(MakeUserError("RamCannotInstallItemForAnother"))); } // corp hangar permission if( (installedItem->flag() == flagCorpSecurityAccessGroup2 && (c->GetCorpRole() & corpRoleHangarCanTake2) != corpRoleHangarCanTake2) || (installedItem->flag() == flagCorpSecurityAccessGroup3 && (c->GetCorpRole() & corpRoleHangarCanTake3) != corpRoleHangarCanTake3) || (installedItem->flag() == flagCorpSecurityAccessGroup4 && (c->GetCorpRole() & corpRoleHangarCanTake4) != corpRoleHangarCanTake4) || (installedItem->flag() == flagCorpSecurityAccessGroup5 && (c->GetCorpRole() & corpRoleHangarCanTake5) != corpRoleHangarCanTake5) || (installedItem->flag() == flagCorpSecurityAccessGroup6 && (c->GetCorpRole() & corpRoleHangarCanTake6) != corpRoleHangarCanTake6) || (installedItem->flag() == flagCorpSecurityAccessGroup7 && (c->GetCorpRole() & corpRoleHangarCanTake7) != corpRoleHangarCanTake7) ) throw(PyException(MakeUserError("RamAccessDeniedToBOMHangar"))); // large location check if(IsStation(args.installationContainerID)) { if(/*args.isCorpJob && */installedItem->flag() == flagCargoHold) throw(PyException(MakeUserError("RamCorpInstalledItemNotInCargo"))); if(installedItem->locationID() != (uint32)args.installationContainerID) { if((uint32)args.installationContainerID == c->GetLocationID()) { std::map<std::string, PyRep *> exceptArgs; exceptArgs["location"] = new PyString(m_db.GetStationName(args.installationContainerID)); if(args.isCorpJob) throw(PyException(MakeUserError("RamCorpInstalledItemWrongLocation", exceptArgs))); else throw(PyException(MakeUserError("RamInstalledItemWrongLocation", exceptArgs))); } else throw(PyException(MakeUserError("RamRemoteInstalledItemNotInStation"))); } else { if(args.isCorpJob) { if(installedItem->flag() < flagCorpSecurityAccessGroup2 || installedItem->flag() > flagCorpSecurityAccessGroup7) { if((uint32)args.installationContainerID == c->GetLocationID()) { std::map<std::string, PyRep *> exceptArgs; exceptArgs["location"] = new PyString(m_db.GetStationName(args.installationContainerID)); throw(PyException(MakeUserError("RamCorpInstalledItemWrongLocation", exceptArgs))); } else throw(PyException(MakeUserError("RamRemoteInstalledItemNotInOffice"))); } } else { if(installedItem->flag() != flagHangar) { if((uint32)args.installationInvLocationID == c->GetLocationID()) { std::map<std::string, PyRep *> exceptArgs; exceptArgs["location"] = new PyString(m_db.GetStationName(args.installationContainerID)); throw(PyException(MakeUserError("RamInstalledItemWrongLocation", exceptArgs))); } else { throw(PyException(MakeUserError("RamRemoteInstalledItemInStationNotHangar"))); } } } } } else if((uint32)args.installationContainerID == c->GetShipID()) { if(c->GetChar()->flag() != flagPilot) throw(PyException(MakeUserError("RamAccessDeniedNotPilot"))); if(installedItem->locationID() != (uint32)args.installationContainerID) throw(PyException(MakeUserError("RamInstalledItemMustBeInShip"))); } else { // here should be stuff around POS, but I dont certainly know how it should work, so ... // RamInstalledItemBadLocationStructure // RamInstalledItemInStructureNotInContainer // RamInstalledItemInStructureUnknownLocation } // BOM LOCATION CHECK // ******************* // corp hangar permission if( (bomLocation.flag == flagCorpSecurityAccessGroup2 && (c->GetCorpRole() & corpRoleHangarCanTake2) != corpRoleHangarCanTake2) || (bomLocation.flag == flagCorpSecurityAccessGroup3 && (c->GetCorpRole() & corpRoleHangarCanTake3) != corpRoleHangarCanTake3) || (bomLocation.flag == flagCorpSecurityAccessGroup4 && (c->GetCorpRole() & corpRoleHangarCanTake4) != corpRoleHangarCanTake4) || (bomLocation.flag == flagCorpSecurityAccessGroup5 && (c->GetCorpRole() & corpRoleHangarCanTake5) != corpRoleHangarCanTake5) || (bomLocation.flag == flagCorpSecurityAccessGroup6 && (c->GetCorpRole() & corpRoleHangarCanTake6) != corpRoleHangarCanTake6) || (bomLocation.flag == flagCorpSecurityAccessGroup7 && (c->GetCorpRole() & corpRoleHangarCanTake7) != corpRoleHangarCanTake7) ) throw(PyException(MakeUserError("RamAccessDeniedToBOMHangar"))); }
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; } }