1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851 |
- #ifdef PRECOMPILEDHEADERS
- #include "Tactical All.h"
- #else
- #include "Types.h"
- #include "stdlib.h"
- #include "Arms Dealer Init.h"
- #include "String.h"
- #include "Debug.h"
- #include "Random.h"
- #include "Weapons.h"
- #include "FileMan.h"
- #include "Game Clock.h"
- #include "ArmsDealerInvInit.h"
- #include "Message.h"
- #include "soldier profile.h"
- #include "Handle Items.h"
- #endif
- // To reduce memory fragmentation from frequent MemRealloc(), we allocate memory for more than one special slot each
- // time we run out of space. Odds are that if we need one, we'll need another soon.
- #define SPECIAL_ITEMS_ALLOCED_AT_ONCE 3
- // Once allocated, the special item slots remain allocated for the duration of the game, or until the dealer dies.
- // This is a little bit wasteful, but saves an awful lot of hassles, and avoid unnecessary memory fragmentation
- #define MIN_REPAIR_TIME_IN_MINUTES 15 // minutes
- #define MIN_REPAIR_COST 10 // dollars
- // price classes
- #define PRICE_CLASS_JUNK 0
- #define PRICE_CLASS_CHEAP 1
- #define PRICE_CLASS_EXPENSIVE 2
- void ConvertCreatureBloodToElixir( void );
- UINT8 gubLastSpecialItemAddedAtElement = 255;
- // THIS STRUCTURE HAS UNCHANGING INFO THAT DOESN'T GET SAVED/RESTORED/RESET
- ARMS_DEALER_INFO ArmsDealerInfo[ NUM_ARMS_DEALERS ] =
- {
- //Buying Selling Merc ID# Type Initial Flags
- //Price Price Of Cash
- //Modifier Modifier Dealer
- /* Tony */ { 0.75f, 1.25f, TONY, ARMS_DEALER_BUYS_SELLS, 15000, ARMS_DEALER_SOME_USED_ITEMS | ARMS_DEALER_GIVES_CHANGE },
- /* Franz Hinkle */ { 1.0f, 1.5f, FRANZ, ARMS_DEALER_BUYS_SELLS, 5000, ARMS_DEALER_SOME_USED_ITEMS | ARMS_DEALER_GIVES_CHANGE },
- /* Keith Hemps */ { 0.75f, 1.0f, KEITH, ARMS_DEALER_BUYS_SELLS, 1500, ARMS_DEALER_ONLY_USED_ITEMS | ARMS_DEALER_GIVES_CHANGE },
- /* Jake Cameron */ { 0.8f, 1.1f, JAKE, ARMS_DEALER_BUYS_SELLS, 2500, ARMS_DEALER_ONLY_USED_ITEMS | ARMS_DEALER_GIVES_CHANGE },
- /* Gabby Mulnick*/ { 1.0f, 1.0f, GABBY, ARMS_DEALER_BUYS_SELLS, 3000, ARMS_DEALER_GIVES_CHANGE },
- /* Devin Connell*/ { 0.75f, 1.25f, DEVIN, ARMS_DEALER_SELLS_ONLY, 5000, ARMS_DEALER_GIVES_CHANGE },
- /* Howard Filmore*/ { 1.0f, 1.0f, HOWARD, ARMS_DEALER_SELLS_ONLY, 3000, ARMS_DEALER_GIVES_CHANGE },
- /* Sam Rozen */ { 1.0f, 1.0f, SAM, ARMS_DEALER_SELLS_ONLY, 3000, ARMS_DEALER_GIVES_CHANGE },
- /* Frank */ { 1.0f, 1.0f, FRANK, ARMS_DEALER_SELLS_ONLY, 500, ARMS_DEALER_ACCEPTS_GIFTS },
- /* Bar Bro 1 */ { 1.0f, 1.0f, HERVE, ARMS_DEALER_SELLS_ONLY, 250, ARMS_DEALER_ACCEPTS_GIFTS },
- /* Bar Bro 2 */ { 1.0f, 1.0f, PETER, ARMS_DEALER_SELLS_ONLY, 250, ARMS_DEALER_ACCEPTS_GIFTS },
- /* Bar Bro 3 */ { 1.0f, 1.0f, ALBERTO, ARMS_DEALER_SELLS_ONLY, 250, ARMS_DEALER_ACCEPTS_GIFTS },
- /* Bar Bro 4 */ { 1.0f, 1.0f, CARLO, ARMS_DEALER_SELLS_ONLY, 250, ARMS_DEALER_ACCEPTS_GIFTS },
- /* Micky O'Brien*/ { 1.0f, 1.4f, MICKY, ARMS_DEALER_BUYS_ONLY, 10000, ARMS_DEALER_HAS_NO_INVENTORY | ARMS_DEALER_GIVES_CHANGE },
- //Repair Repair
- //Speed Cost
- /* Arnie Brunzwell*/{ 0.1f, 0.8f, ARNIE, ARMS_DEALER_REPAIRS, 1500, ARMS_DEALER_HAS_NO_INVENTORY | ARMS_DEALER_GIVES_CHANGE },
- /* Fredo */ { 0.6f, 0.6f, FREDO, ARMS_DEALER_REPAIRS, 1000, ARMS_DEALER_HAS_NO_INVENTORY | ARMS_DEALER_GIVES_CHANGE },
- /* Perko */ { 1.0f, 0.4f, PERKO, ARMS_DEALER_REPAIRS, 1000, ARMS_DEALER_HAS_NO_INVENTORY | ARMS_DEALER_GIVES_CHANGE },
- /* Elgin */ { 1.0f, 1.0f, DRUGGIST, ARMS_DEALER_SELLS_ONLY, 500, ARMS_DEALER_ACCEPTS_GIFTS },
- /* Manny */ { 1.0f, 1.0f, MANNY, ARMS_DEALER_SELLS_ONLY, 500, ARMS_DEALER_ACCEPTS_GIFTS },
- };
- // THESE GET SAVED/RESTORED/RESET
- ARMS_DEALER_STATUS gArmsDealerStatus[ NUM_ARMS_DEALERS ];
- DEALER_ITEM_HEADER gArmsDealersInventory[ NUM_ARMS_DEALERS ][ MAXITEMS ];
- void InitializeOneArmsDealer( UINT8 ubArmsDealer );
- void AddAmmoToArmsDealerInventory( UINT8 ubArmsDealer, UINT16 usItemIndex, UINT8 ubShotsLeft );
- void AddItemToArmsDealerInventory( UINT8 ubArmsDealer, UINT16 usItemIndex, SPECIAL_ITEM_INFO *pSpclItemInfo, UINT8 ubHowMany );
- void AddSpecialItemToArmsDealerInventoryAtElement( UINT8 ubArmsDealer, UINT16 usItemIndex, UINT8 ubElement, SPECIAL_ITEM_INFO *pSpclItemInfo );
- void RemoveRandomItemFromArmsDealerInventory( UINT8 ubArmsDealer, UINT16 usItemIndex, UINT8 ubHowMany );
- void DailyCheckOnItemQuantities();
- void SimulateArmsDealerCustomer();
- BOOLEAN AdjustCertainDealersInventory();
- void LimitArmsDealersInventory( UINT8 ubArmsDealer, UINT32 uDealerItemType, UINT8 ubMaxNumberOfItemType );
- void GuaranteeAtLeastOneItemOfType( UINT8 ubArmsDealer, UINT32 uiDealerItemType );
- void GuaranteeAtLeastXItemsOfIndex( UINT8 ubArmsDealer, UINT16 usItemIndex, UINT8 ubHowMany );
- BOOLEAN AllocMemsetSpecialItemArray( DEALER_ITEM_HEADER *pDealerItem, UINT8 ubElementsNeeded );
- BOOLEAN ResizeSpecialItemArray( DEALER_ITEM_HEADER *pDealerItem, UINT8 ubElementsNeeded );
- void FreeSpecialItemArray( DEALER_ITEM_HEADER *pDealerItem );
- void ArmsDealerGetsFreshStock( UINT8 ubArmsDealer, UINT16 usItemIndex, UINT8 ubNumItems );
- BOOLEAN ItemContainsLiquid( UINT16 usItemIndex );
- UINT8 DetermineDealerItemCondition( UINT8 ubArmsDealer, UINT16 usItemIndex );
- BOOLEAN IsItemInfoSpecial( SPECIAL_ITEM_INFO *pSpclItemInfo );
- BOOLEAN DoesItemAppearInDealerInventoryList( UINT8 ubArmsDealer, UINT16 usItemIndex, BOOLEAN fPurchaseFromPlayer );
- BOOLEAN LoadIncompleteArmsDealersStatus( HWFILE hFile, BOOLEAN fIncludesElgin, BOOLEAN fIncludesManny );
- //INT16 GetSpecialItemFromArmsDealerInventory( UINT8 ubArmsDealer, UINT16 usItemIndex, SPECIAL_ITEM_INFO *pSpclItemInfo );
- void GuaranteeMinimumAlcohol( UINT8 ubArmsDealer );
- BOOLEAN ItemIsARocketRifle( INT16 sItemIndex );
- BOOLEAN GetArmsDealerShopHours( UINT8 ubArmsDealer, UINT32 *puiOpeningTime, UINT32 *puiClosingTime );
- void InitAllArmsDealers()
- {
- UINT8 ubArmsDealer;
- //Memset all dealers' status tables to zeroes
- memset( gArmsDealerStatus, 0, sizeof( gArmsDealerStatus ) );
- //Memset all dealers' inventory tables to zeroes
- memset( gArmsDealersInventory, 0, sizeof( gArmsDealersInventory ) );
- //Initialize the initial status & inventory for each of the arms dealers
- for( ubArmsDealer = 0; ubArmsDealer < NUM_ARMS_DEALERS; ubArmsDealer++ )
- {
- InitializeOneArmsDealer( ubArmsDealer );
- }
- //make sure certain items are in stock and certain limits are respected
- AdjustCertainDealersInventory( );
- }
- void InitializeOneArmsDealer( UINT8 ubArmsDealer )
- {
- UINT16 usItemIndex;
- UINT8 ubNumItems=0;
- #ifdef JA2DEMO
- if ( ubArmsDealer != ARMS_DEALER_JAKE)
- {
- return;
- }
- #endif
- memset( &( gArmsDealerStatus[ ubArmsDealer ] ), 0, sizeof( ARMS_DEALER_STATUS ) );
- memset( &( gArmsDealersInventory[ ubArmsDealer ] ), 0, sizeof( DEALER_ITEM_HEADER ) * MAXITEMS );
- //Reset the arms dealers cash on hand to the default initial value
- gArmsDealerStatus[ ubArmsDealer ].uiArmsDealersCash = ArmsDealerInfo[ ubArmsDealer ].iInitialCash;
- //if the arms dealer isn't supposed to have any items (includes all repairmen)
- if( ArmsDealerInfo[ ubArmsDealer ].uiFlags & ARMS_DEALER_HAS_NO_INVENTORY )
- {
- return;
- }
- //loop through all the item types
- for( usItemIndex = 1; usItemIndex < MAXITEMS; usItemIndex++ )
- {
- //Can the item be sold by the arms dealer
- if( CanDealerTransactItem( ubArmsDealer, usItemIndex, FALSE ) )
- {
- //Setup an initial amount for the items (treat items as new, how many are used isn't known yet)
- ubNumItems = DetermineInitialInvItems( ubArmsDealer, usItemIndex, GetDealersMaxItemAmount( ubArmsDealer, usItemIndex ), FALSE );
- //if there are any initial items
- if( ubNumItems > 0 )
- {
- ArmsDealerGetsFreshStock( ubArmsDealer, usItemIndex, ubNumItems );
- }
- }
- }
- }
- void ShutDownArmsDealers()
- {
- UINT8 ubArmsDealer;
- UINT16 usItemIndex;
- // loop through all the dealers
- for( ubArmsDealer=0; ubArmsDealer<NUM_ARMS_DEALERS; ubArmsDealer++ )
- {
- #ifdef JA2DEMO
- if ( ubArmsDealer != ARMS_DEALER_JAKE)
- {
- continue;
- }
- #endif
- //loop through all the item types
- for( usItemIndex = 1; usItemIndex < MAXITEMS; usItemIndex++ )
- {
- if( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubElementsAlloced > 0 )
- {
- FreeSpecialItemArray( &gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ] );
- }
- }
- }
- }
- BOOLEAN SaveArmsDealerInventoryToSaveGameFile( HWFILE hFile )
- {
- UINT32 uiNumBytesWritten;
- UINT8 ubArmsDealer;
- UINT16 usItemIndex;
- //Save the arms dealers status
- if (!FileWrite( hFile, gArmsDealerStatus, sizeof( gArmsDealerStatus ), &uiNumBytesWritten ))
- {
- return( FALSE );
- }
- //save the dealers inventory item headers (all at once)
- if (!FileWrite( hFile, gArmsDealersInventory, sizeof( gArmsDealersInventory ), &uiNumBytesWritten ))
- {
- return( FALSE );
- }
- //loop through all the dealers inventories
- for( ubArmsDealer=0; ubArmsDealer<NUM_ARMS_DEALERS; ubArmsDealer++ )
- {
- //loop through this dealer's individual items
- for(usItemIndex = 1; usItemIndex < MAXITEMS; usItemIndex++ )
- {
- //if there are any special item elements allocated for this item, save them
- if( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubElementsAlloced > 0 )
- {
- if (!FileWrite( hFile, &gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[0], sizeof( DEALER_SPECIAL_ITEM ) * gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubElementsAlloced, &uiNumBytesWritten ))
- {
- return( FALSE );
- }
- }
- }
- }
- return( TRUE );
- }
- BOOLEAN LoadArmsDealerInventoryFromSavedGameFile( HWFILE hFile, BOOLEAN fIncludesElgin, BOOLEAN fIncludesManny )
- {
- UINT32 uiNumBytesRead;
- UINT8 ubArmsDealer;
- UINT16 usItemIndex;
- //Free all the dealers special inventory arrays
- ShutDownArmsDealers();
- // Elgin was added to the dealers list in Game Version #54, enlarging these 2 tables...
- // Manny was added to the dealers list in Game Version #55, enlarging these 2 tables...
- if ( fIncludesElgin && fIncludesManny )
- {
- // info for all dealers is in the save file
- //Load the arms dealers status
- if ( !FileRead( hFile, gArmsDealerStatus, sizeof( gArmsDealerStatus ), &uiNumBytesRead ))
- {
- return( FALSE );
- }
- //load the dealers inventory item headers (all at once)
- if ( !FileRead( hFile, gArmsDealersInventory, sizeof( gArmsDealersInventory ), &uiNumBytesRead ))
- {
- return( FALSE );
- }
- }
- else
- {
- if ( !LoadIncompleteArmsDealersStatus( hFile, fIncludesElgin, fIncludesManny ) )
- {
- return( FALSE );
- }
- }
- //loop through all the dealers inventories
- for( ubArmsDealer=0; ubArmsDealer<NUM_ARMS_DEALERS; ubArmsDealer++ )
- {
- //loop through this dealer's individual items
- for(usItemIndex = 1; usItemIndex < MAXITEMS; usItemIndex++ )
- {
- //if there are any elements allocated for this item, load them
- if( gArmsDealersInventory[ubArmsDealer][usItemIndex].ubElementsAlloced > 0 )
- {
- //Allocate memory for the inventory
- if ( !AllocMemsetSpecialItemArray( &gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ], gArmsDealersInventory[ubArmsDealer][usItemIndex].ubElementsAlloced ))
- return(FALSE);
- if (!FileRead( hFile, &gArmsDealersInventory[ubArmsDealer][usItemIndex].SpecialItem[0], sizeof( DEALER_SPECIAL_ITEM ) * gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubElementsAlloced, &uiNumBytesRead ))
- {
- return( FALSE );
- }
- }
- }
- }
- return( TRUE );
- }
- void DailyUpdateOfArmsDealersInventory()
- {
- // if Gabby has creature blood, start turning it into extra elixir
- ConvertCreatureBloodToElixir();
- //Simulate other customers buying inventory from the dealer
- SimulateArmsDealerCustomer();
- //if there are some items that are out of stock, order some more
- DailyCheckOnItemQuantities();
- //make sure certain items are in stock and certain limits are respected
- AdjustCertainDealersInventory( );
- }
- // Once a day, loop through each dealer's inventory items and possibly sell some
- void SimulateArmsDealerCustomer()
- {
- UINT8 ubArmsDealer=0;
- UINT16 usItemIndex;
- UINT8 ubItemsSold=0;
- UINT8 ubElement;
- SPECIAL_ITEM_INFO SpclItemInfo;
- //loop through all the arms dealers
- for( ubArmsDealer=0;ubArmsDealer<NUM_ARMS_DEALERS;ubArmsDealer++ )
- {
- if( gArmsDealerStatus[ ubArmsDealer ].fOutOfBusiness )
- continue;
- //if the arms dealer isn't supposed to have any items (includes all repairmen)
- if( ArmsDealerInfo[ ubArmsDealer ].uiFlags & ARMS_DEALER_HAS_NO_INVENTORY )
- continue;
- //loop through all items of the same type
- for( usItemIndex = 1; usItemIndex < MAXITEMS; usItemIndex++ )
- {
- //if there are some of these in stock
- if( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems > 0)
- {
- // first, try to sell all the new (perfect) ones
- if ( usItemIndex == JAR_ELIXIR )
- {
- // only allow selling of standard # of items so those converted from blood given by player will be available
- ubItemsSold = HowManyItemsAreSold( ubArmsDealer, usItemIndex, (UINT8) __min( 3, gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubPerfectItems), FALSE);
- }
- else
- {
- ubItemsSold = HowManyItemsAreSold( ubArmsDealer, usItemIndex, gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubPerfectItems, FALSE);
- }
- if ( ubItemsSold > 0)
- {
- // create item info describing a perfect item
- SetSpecialItemInfoToDefaults( &SpclItemInfo );
- //Now remove that many NEW ones (condition 100) of that item
- RemoveItemFromArmsDealerInventory( ubArmsDealer, usItemIndex, &SpclItemInfo, ubItemsSold);
- }
- // next, try to sell all the used ones, gotta do these one at a time so we can remove them by element
- for ( ubElement = 0; ubElement < gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubElementsAlloced; ubElement++ )
- {
- // don't worry about negative condition, repairmen can't come this far, they don't sell!
- if ( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].fActive )
- {
- // try selling just this one
- if (HowManyItemsAreSold( ubArmsDealer, usItemIndex, 1, TRUE) > 0)
- {
- //Sold, now remove that particular USED one!
- RemoveSpecialItemFromArmsDealerInventoryAtElement( ubArmsDealer, usItemIndex, ubElement );
- }
- }
- }
- }
- }
- }
- }
- void DailyCheckOnItemQuantities()
- {
- UINT8 ubArmsDealer;
- UINT16 usItemIndex;
- UINT8 ubMaxSupply;
- UINT8 ubNumItems;
- UINT32 uiArrivalDay;
- BOOLEAN fPrevElig;
- UINT8 ubReorderDays;
- //loop through all the arms dealers
- for( ubArmsDealer=0;ubArmsDealer<NUM_ARMS_DEALERS;ubArmsDealer++ )
- {
- if( gArmsDealerStatus[ ubArmsDealer ].fOutOfBusiness )
- continue;
- //Reset the arms dealers cash on hand to the default initial value
- gArmsDealerStatus[ ubArmsDealer ].uiArmsDealersCash = ArmsDealerInfo[ ubArmsDealer ].iInitialCash;
- //if the arms dealer isn't supposed to have any items (includes all repairmen)
- if( ArmsDealerInfo[ ubArmsDealer ].uiFlags & ARMS_DEALER_HAS_NO_INVENTORY )
- continue;
- //loop through all items of the same type
- for( usItemIndex = 1; usItemIndex < MAXITEMS; usItemIndex++ )
- {
- //if the dealer can sell the item type
- if( CanDealerTransactItem( ubArmsDealer, usItemIndex, FALSE ) )
- {
- //if there are no items on order
- if ( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubQtyOnOrder == 0 )
- {
- ubMaxSupply = GetDealersMaxItemAmount( ubArmsDealer, usItemIndex );
- //if the qty on hand is half the desired amount or fewer
- if( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems <= (UINT32)( ubMaxSupply / 2 ) )
- {
- // remember value of the "previously eligible" flag
- fPrevElig = gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].fPreviouslyEligible;
- //determine if the item can be restocked (assume new, use items aren't checked for until the stuff arrives)
- if (ItemTransactionOccurs( ubArmsDealer, usItemIndex, DEALER_BUYING, FALSE ))
- {
- // figure out how many items to reorder (items are reordered an entire batch at a time)
- ubNumItems = HowManyItemsToReorder( ubMaxSupply, gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems );
- // if this is the first day the player is eligible to have access to this thing
- if ( !fPrevElig )
- {
- // eliminate the ordering delay and stock the items instantly!
- // This is just a way to reward the player right away for making progress without the reordering lag...
- ArmsDealerGetsFreshStock( ubArmsDealer, usItemIndex, ubNumItems );
- }
- else
- {
- if ( ( ubArmsDealer == ARMS_DEALER_TONY ) || ( ubArmsDealer == ARMS_DEALER_DEVIN ) )
- {
- // the stuff Tony and Devin sell is imported, so it takes longer to arrive (for game balance)
- ubReorderDays = ( UINT8) ( 2 + Random( 2 ) ); // 2-3 days
- }
- else
- {
- ubReorderDays = ( UINT8) ( 1 + Random( 2 ) ); // 1-2 days
- }
- //Determine when the inventory should arrive
- uiArrivalDay = GetWorldDay() + ubReorderDays; // consider changing this to minutes
- // post new order
- gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubQtyOnOrder = ubNumItems;
- gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].uiOrderArrivalTime = uiArrivalDay;
- }
- }
- }
- }
- else //items are on order
- {
- //and today is the day the items come in
- if( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].uiOrderArrivalTime >= GetWorldDay() )
- {
- ArmsDealerGetsFreshStock( ubArmsDealer, usItemIndex, gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubQtyOnOrder);
- //reset order
- gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubQtyOnOrder = 0;
- gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].uiOrderArrivalTime = 0;
- }
- }
- }
- }
- }
- }
- void ConvertCreatureBloodToElixir( void )
- {
- UINT8 ubBloodAvailable;
- UINT8 ubAmountToConvert;
- SPECIAL_ITEM_INFO SpclItemInfo;
- ubBloodAvailable = gArmsDealersInventory[ ARMS_DEALER_GABBY ][ JAR_CREATURE_BLOOD ].ubTotalItems;
- if ( ubBloodAvailable )
- {
- // start converting blood into elixir!
- //ubAmountToConvert = (UINT8) __min( 5 + Random( 3 ), ubBloodAvailable );
- ubAmountToConvert = ubBloodAvailable;
- // create item info describing a perfect item
- SetSpecialItemInfoToDefaults( &SpclItemInfo );
- //Now remove that many NEW ones (condition 100) of that item
- RemoveItemFromArmsDealerInventory( ARMS_DEALER_GABBY, JAR_CREATURE_BLOOD, &SpclItemInfo, ubAmountToConvert );
- ArmsDealerGetsFreshStock( ARMS_DEALER_GABBY, JAR_ELIXIR, ubAmountToConvert );
- }
- }
- BOOLEAN AdjustCertainDealersInventory( )
- {
- //Adjust Tony's items (this restocks *instantly* 1/day, doesn't use the reorder system)
- GuaranteeAtLeastOneItemOfType( ARMS_DEALER_TONY, ARMS_DEALER_BIG_GUNS );
- LimitArmsDealersInventory( ARMS_DEALER_TONY, ARMS_DEALER_BIG_GUNS, 2 );
- LimitArmsDealersInventory( ARMS_DEALER_TONY, ARMS_DEALER_HANDGUNCLASS, 3 );
- LimitArmsDealersInventory( ARMS_DEALER_TONY, ARMS_DEALER_AMMO, 8 );
- //Adjust all bartenders' alcohol levels to a minimum
- GuaranteeMinimumAlcohol( ARMS_DEALER_FRANK );
- GuaranteeMinimumAlcohol( ARMS_DEALER_BAR_BRO_1 );
- GuaranteeMinimumAlcohol( ARMS_DEALER_BAR_BRO_2 );
- GuaranteeMinimumAlcohol( ARMS_DEALER_BAR_BRO_3 );
- GuaranteeMinimumAlcohol( ARMS_DEALER_BAR_BRO_4 );
- GuaranteeMinimumAlcohol( ARMS_DEALER_ELGIN );
- GuaranteeMinimumAlcohol( ARMS_DEALER_MANNY );
- //make sure Sam (hardware guy) has at least one empty jar
- GuaranteeAtLeastXItemsOfIndex( ARMS_DEALER_SAM, JAR, 1 );
- if ( CheckFact( FACT_ESTONI_REFUELLING_POSSIBLE, 0 ) )
- {
- // gas is restocked regularly, unlike most items
- GuaranteeAtLeastXItemsOfIndex( ARMS_DEALER_JAKE, GAS_CAN, ( UINT8 ) ( 4 + Random( 3 ) ) );
- }
- //If the player hasn't bought a video camera from Franz yet, make sure Franz has one to sell
- if( !( gArmsDealerStatus[ ARMS_DEALER_FRANZ ].ubSpecificDealerFlags & ARMS_DEALER_FLAG__FRANZ_HAS_SOLD_VIDEO_CAMERA_TO_PLAYER ) )
- {
- GuaranteeAtLeastXItemsOfIndex( ARMS_DEALER_FRANZ, VIDEO_CAMERA, 1 );
- }
- #ifdef JA2DEMO
- {
- // Adjust Jake's inventory (for demo only)
- SPECIAL_ITEM_INFO SpclItemInfo;
- // create item info describing a perfect item
- SetSpecialItemInfoToDefaults( &SpclItemInfo );
- // These items are to be in perfect working order (even though he's a junk dealer)
- AddItemToArmsDealerInventory( ARMS_DEALER_JAKE, SILENCER, &SpclItemInfo, (UINT8)( 2 + Random( 2 ) ) );
- AddItemToArmsDealerInventory( ARMS_DEALER_JAKE, LOCKSMITHKIT, &SpclItemInfo, 1 );
- // ArmsDealerGetsFreshStock( ARMS_DEALER_JAKE, SILENCER, (UINT8)( 2 + Random( 2 ) ) );
- // ArmsDealerGetsFreshStock( ARMS_DEALER_JAKE, LOCKSMITHKIT, 1);
- }
- #endif
- return( TRUE );
- }
- void LimitArmsDealersInventory( UINT8 ubArmsDealer, UINT32 uiDealerItemType, UINT8 ubMaxNumberOfItemType )
- {
- UINT16 usItemIndex=0;
- UINT32 uiItemsToRemove=0;
- SPECIAL_ITEM_INFO SpclItemInfo;
- UINT16 usAvailableItem[ MAXITEMS ] = { NOTHING };
- UINT8 ubNumberOfAvailableItem[ MAXITEMS ] = { 0 };
- UINT32 uiTotalNumberOfItems = 0, uiRandomChoice;
- UINT32 uiNumAvailableItems = 0, uiIndex;
- // not permitted for repair dealers - would take extra code to avoid counting items under repair!
- Assert( !DoesDealerDoRepairs( ubArmsDealer ) );
- if( gArmsDealerStatus[ ubArmsDealer ].fOutOfBusiness )
- return;
- //loop through all items of the same class and count the number in stock
- for( usItemIndex = 1; usItemIndex < MAXITEMS; usItemIndex++ )
- {
- //if there is some items in stock
- if( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems > 0)
- {
- //if the item is of the same dealer item type
- if( uiDealerItemType & GetArmsDealerItemTypeFromItemNumber( usItemIndex ) )
- {
- usAvailableItem[ uiNumAvailableItems ] = usItemIndex;
- //if the dealer item type is ammo
- if( uiDealerItemType == ARMS_DEALER_AMMO )
- {
- // all ammo of same type counts as only one item
- ubNumberOfAvailableItem[ uiNumAvailableItems ] = 1;
- uiTotalNumberOfItems++;
- }
- else
- {
- // items being repaired don't count against the limit
- ubNumberOfAvailableItem[ uiNumAvailableItems ] = gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems;
- uiTotalNumberOfItems += ubNumberOfAvailableItem[ uiNumAvailableItems ];
- }
- uiNumAvailableItems++;
- }
- }
- }
- //if there is more of the given type than we want
- if( uiNumAvailableItems > ubMaxNumberOfItemType )
- {
- uiItemsToRemove = uiNumAvailableItems - ubMaxNumberOfItemType;
- do
- {
- uiRandomChoice = Random( uiTotalNumberOfItems );
- for ( uiIndex = 0; uiIndex < uiNumAvailableItems; uiIndex++ )
- {
- if ( uiRandomChoice <= ubNumberOfAvailableItem[ uiIndex ] )
- {
- usItemIndex = usAvailableItem[ uiIndex ];
- if ( uiDealerItemType == ARMS_DEALER_AMMO )
- {
- // remove all of them, since each ammo item counts as only one "item" here
- // create item info describing a perfect item
- SetSpecialItemInfoToDefaults( &SpclItemInfo );
- // ammo will always be only condition 100, there's never any in special slots
- RemoveItemFromArmsDealerInventory( ubArmsDealer, usItemIndex, &SpclItemInfo, gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems );
- }
- else
- {
- // pick 1 random one, don't care about its condition
- RemoveRandomItemFromArmsDealerInventory( ubArmsDealer, usItemIndex, 1 );
- }
- // now remove entry from the array by replacing it with the last and decrementing
- // the size of the array
- usAvailableItem[ uiIndex ] = usAvailableItem[ uiNumAvailableItems - 1 ];
- ubNumberOfAvailableItem[ uiIndex ] = ubNumberOfAvailableItem[ uiNumAvailableItems - 1 ];
- uiNumAvailableItems--;
- // decrement count of # of items to remove
- uiItemsToRemove--;
- break; // and out of 'for' loop
- }
- else
- {
- // next item!
- uiRandomChoice -= ubNumberOfAvailableItem[ uiIndex ];
- }
- }
- /*
- //loop through all items of the same type
- for( usItemIndex = 1; usItemIndex < MAXITEMS; usItemIndex++ )
- {
- //if there are some non-repairing items in stock
- if( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems )
- {
- //if the item is of the same dealer item type
- if( uiDealerItemType & GetArmsDealerItemTypeFromItemNumber( usItemIndex ) )
- {
- // a random chance that the item will be removed
- if( Random( 100 ) < 30 )
- {
- //remove the item
- //if the dealer item type is ammo
- if( uiDealerItemType == ARMS_DEALER_AMMO )
- {
- // remove all of them, since each ammo item counts as only one "item" here
- // create item info describing a perfect item
- SetSpecialItemInfoToDefaults( &SpclItemInfo );
- // ammo will always be only condition 100, there's never any in special slots
- RemoveItemFromArmsDealerInventory( ubArmsDealer, usItemIndex, &SpclItemInfo, gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems );
- }
- else
- {
- // pick 1 random one, don't care about its condition
- RemoveRandomItemFromArmsDealerInventory( ubArmsDealer, usItemIndex, 1 );
- }
- uiItemsToRemove--;
- if( uiItemsToRemove == 0)
- break;
- }
- }
- }
- }
- */
- } while (uiItemsToRemove > 0);
- }
- }
- void GuaranteeAtLeastOneItemOfType( UINT8 ubArmsDealer, UINT32 uiDealerItemType )
- {
- UINT16 usItemIndex;
- UINT8 ubChance;
- BOOLEAN fFoundEligibleItemOfSameType = FALSE;
- BOOLEAN fItemHasBeenAdded = FALSE;
- BOOLEAN fFailedOnce = FALSE;
- UINT16 usAvailableItem[ MAXITEMS ] = { NOTHING };
- UINT8 ubChanceForAvailableItem[ MAXITEMS ] = { 0 };
- UINT32 uiTotalChances = 0;
- UINT32 uiNumAvailableItems = 0, uiIndex, uiRandomChoice;
-
- // not permitted for repair dealers - would take extra code to avoid counting items under repair!
- Assert( !DoesDealerDoRepairs( ubArmsDealer ) );
- if( gArmsDealerStatus[ ubArmsDealer ].fOutOfBusiness )
- return;
- //loop through all items of the same type
- for( usItemIndex = 1; usItemIndex < MAXITEMS; usItemIndex++ )
- {
- //if the item is of the same dealer item type
- if( uiDealerItemType & GetArmsDealerItemTypeFromItemNumber( usItemIndex ) )
- {
- //if there are any of these in stock
- if( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems > 0 )
- {
- //there is already at least 1 item of that type, return
- return;
- }
- // if he can stock it (it appears in his inventory list)
- if( GetDealersMaxItemAmount( ubArmsDealer, usItemIndex ) > 0)
- {
- // and the stage of the game gives him a chance to have it (assume new)
- ubChance = ChanceOfItemTransaction( ubArmsDealer, usItemIndex, DEALER_BUYING, FALSE );
- if ( ubChance > 0 )
- {
- usAvailableItem[ uiNumAvailableItems ] = usItemIndex;
- ubChanceForAvailableItem[ uiNumAvailableItems ] = ubChance;
- uiNumAvailableItems++;
- uiTotalChances += ubChance;
- }
- }
- }
- }
- // if there aren't any such items, the following loop would never finish, so quit before trying it!
- if (uiNumAvailableItems == 0)
- {
- return;
- }
- // CJC: randomly pick one of available items by weighted random selection.
- // randomize number within uiTotalChances and then loop forwards till we find that item
- uiRandomChoice = Random( uiTotalChances );
- for ( uiIndex = 0; uiIndex < uiNumAvailableItems; uiIndex++ )
- {
- if ( uiRandomChoice <= ubChanceForAvailableItem[ uiIndex ] )
- {
- ArmsDealerGetsFreshStock( ubArmsDealer, usAvailableItem[ uiIndex ], 1 );
- return;
- }
- else
- {
- // next item!
- uiRandomChoice -= ubChanceForAvailableItem[ uiIndex ];
- }
- }
- // internal logic failure!
- }
- void GuaranteeAtLeastXItemsOfIndex( UINT8 ubArmsDealer, UINT16 usItemIndex, UINT8 ubHowMany )
- {
- // not permitted for repair dealers - would take extra code to avoid counting items under repair!
- Assert( !DoesDealerDoRepairs( ubArmsDealer ) );
- if( gArmsDealerStatus[ ubArmsDealer ].fOutOfBusiness )
- return;
- //if there are any of these in stock
- if( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems >= ubHowMany )
- {
- // have what we need...
- return;
- }
- // if he can stock it (it appears in his inventory list)
- // RESTRICTION REMOVED: Jake must be able to guarantee GAS even though it's not in his list, it's presence is conditional
- // if( GetDealersMaxItemAmount( ubArmsDealer, usItemIndex ) > 0)
- {
- //add the item
- ArmsDealerGetsFreshStock( ubArmsDealer, usItemIndex, (UINT8)( ubHowMany - gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems ) );
- }
- }
- UINT32 GetArmsDealerItemTypeFromItemNumber( UINT16 usItem )
- {
- switch( Item[ usItem ].usItemClass )
- {
- case IC_NONE:
- return( 0 );
- break;
- case IC_GUN:
- switch( Weapon[ Item[ usItem ].ubClassIndex ].ubWeaponClass )
- {
- case HANDGUNCLASS:
- return( ARMS_DEALER_HANDGUNCLASS );
- break;
- case RIFLECLASS:
- if ( ItemIsARocketRifle( usItem ) )
- return( ARMS_DEALER_ROCKET_RIFLE );
- else
- return( ARMS_DEALER_RIFLECLASS );
- break;
- case SHOTGUNCLASS:
- return( ARMS_DEALER_SHOTGUNCLASS );
- break;
- case SMGCLASS:
- return( ARMS_DEALER_SMGCLASS );
- break;
- case MGCLASS:
- return( ARMS_DEALER_MGCLASS );
- break;
- case MONSTERCLASS:
- return( 0 );
- break;
- case KNIFECLASS:
- return( ARMS_DEALER_KNIFECLASS );
- break;
- }
- break;
- case IC_PUNCH:
- if (usItem == NOTHING)
- {
- return( 0 );
- }
- // else treat as blade
- case IC_BLADE:
- case IC_THROWING_KNIFE:
- return( ARMS_DEALER_BLADE );
- break;
- case IC_LAUNCHER:
- return( ARMS_DEALER_LAUNCHER );
- break;
- case IC_ARMOUR:
- return( ARMS_DEALER_ARMOUR );
- break;
- case IC_MEDKIT:
- return( ARMS_DEALER_MEDKIT );
- break;
- case IC_KIT:
- return( ARMS_DEALER_KIT );
- break;
- case IC_MISC:
- {
- //switch on the type of item
- switch( usItem )
- {
- case BEER:
- case WINE:
- case ALCOHOL:
- return( ARMS_DEALER_ALCOHOL );
- break;
- case METALDETECTOR:
- case LASERSCOPE:
- // case REMDETONATOR:
- return( ARMS_DEALER_ELECTRONICS );
- break;
- case CANTEEN:
- case CROWBAR:
- case WIRECUTTERS:
- return( ARMS_DEALER_HARDWARE );
- break;
- case ADRENALINE_BOOSTER:
- case REGEN_BOOSTER:
- case SYRINGE_3:
- case SYRINGE_4:
- case SYRINGE_5:
- return( ARMS_DEALER_MEDICAL );
- break;
- case SILENCER:
- case SNIPERSCOPE:
- case BIPOD:
- case DUCKBILL:
- return( ARMS_DEALER_ATTACHMENTS );
- break;
- case DETONATOR:
- case REMDETONATOR:
- case REMOTEBOMBTRIGGER:
- return( ARMS_DEALER_DETONATORS );
- break;
- default:
- return( ARMS_DEALER_MISC );
- }
- }
- break;
- case IC_AMMO:
- return( ARMS_DEALER_AMMO );
- break;
- case IC_FACE:
- switch( usItem )
- {
- case EXTENDEDEAR:
- case NIGHTGOGGLES:
- case ROBOT_REMOTE_CONTROL:
- return( ARMS_DEALER_ELECTRONICS );
- break;
- default:
- return( ARMS_DEALER_FACE );
- }
- break;
- case IC_THROWN:
- return( 0 );
- // return( ARMS_DEALER_THROWN );
-
- break;
- case IC_KEY:
- return( 0 );
- // return( ARMS_DEALER_KEY );
- break;
- case IC_GRENADE:
- return( ARMS_DEALER_GRENADE );
- break;
- case IC_BOMB:
- return( ARMS_DEALER_BOMB );
- break;
- case IC_EXPLOSV:
- return( ARMS_DEALER_EXPLOSV );
- break;
- case IC_TENTACLES:
- case IC_MONEY:
- return( 0 );
- break;
- // case IC_APPLIABLE:
- break;
- default:
- AssertMsg( FALSE, String( "GetArmsDealerItemTypeFromItemNumber(), invalid class %d for item %d. DF 0.", Item[ usItem ].usItemClass, usItem ) );
- break;
- }
- return( 0 );
- }
- BOOLEAN IsMercADealer( UINT8 ubMercID )
- {
- UINT8 cnt;
- #ifdef JA2DEMO // Gabby is not a dealer in the demo, but is one in the game
- if( ubMercID == GABBY )
- return( FALSE );
- #endif
- // Manny is not actually a valid dealer unless a particular event sets that fact
- if( ( ubMercID == MANNY ) && !CheckFact( FACT_MANNY_IS_BARTENDER, 0 ) )
- {
- return( FALSE );
- }
- //loop through the list of arms dealers
- for( cnt=0; cnt<NUM_ARMS_DEALERS; cnt++ )
- {
- if( ArmsDealerInfo[ cnt ].ubShopKeeperID == ubMercID )
- return( TRUE );
- }
- return( FALSE );
- }
- INT8 GetArmsDealerIDFromMercID( UINT8 ubMercID )
- {
- INT8 cnt;
- #ifdef JA2DEMO // Gabby is not a dealer in the demo, but is one in the game
- if( ubMercID == GABBY )
- return( -1 );
- #endif
- //loop through the list of arms dealers
- for( cnt=0; cnt<NUM_ARMS_DEALERS; cnt++ )
- {
- if( ArmsDealerInfo[ cnt ].ubShopKeeperID == ubMercID )
- return( cnt );
- }
- return( -1 );
- }
- UINT8 GetTypeOfArmsDealer( UINT8 ubDealerID )
- {
- return( ArmsDealerInfo[ ubDealerID ].ubTypeOfArmsDealer );
- }
- BOOLEAN DoesDealerDoRepairs( UINT8 ubArmsDealer )
- {
- if( ArmsDealerInfo[ ubArmsDealer ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
- return( TRUE );
- else
- return( FALSE );
- }
- /*
- INT16 GetSpecialItemFromArmsDealerInventory( UINT8 ubArmsDealer, UINT16 usItemIndex, SPECIAL_ITEM_INFO *pSpclItemInfo )
- {
- UINT8 ubElement;
- // this function won't find perfect items!
- Assert( IsItemInfoSpecial( pSpclItemInfo ) );
- for( ubElement = 0; ubElement < gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubElementsAlloced; ubElement++ )
- {
- // if this is the one we're looking for
- if( memcmp( &(gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].Info), pSpclItemInfo, sizeof( SPECIAL_ITEM_INFO ) ) == 0 )
- {
- return( ubElement );
- }
- }
- // not found!
- return( -1 );
- }
- */
- BOOLEAN RepairmanIsFixingItemsButNoneAreDoneYet( UINT8 ubProfileID )
- {
- INT8 bArmsDealer;
- BOOLEAN fHaveOnlyUnRepairedItems=FALSE;
- UINT8 ubElement;
- UINT16 usItemIndex;
- bArmsDealer = GetArmsDealerIDFromMercID( ubProfileID );
- if( bArmsDealer == -1 )
- return( FALSE );
- //if the dealer is not a repair dealer, return
- if( !DoesDealerDoRepairs( bArmsDealer ) )
- return( FALSE );
- //loop through the dealers inventory and check if there are only unrepaired items
- for( usItemIndex = 1; usItemIndex < MAXITEMS; usItemIndex++ )
- {
- //if there is some items in stock
- if( gArmsDealersInventory[ bArmsDealer ][ usItemIndex ].ubTotalItems )
- {
- //loop through the array of items
- for( ubElement=0; ubElement< gArmsDealersInventory[ bArmsDealer ][ usItemIndex ].ubElementsAlloced; ubElement++ )
- {
- if ( gArmsDealersInventory[ bArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].fActive )
- {
- //if the items status is below 0, the item is being repaired
- if( gArmsDealersInventory[ bArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].Info.bItemCondition < 0 )
- {
- //if the item has been repaired
- if( gArmsDealersInventory[ bArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].uiRepairDoneTime <= GetWorldTotalMin() )
- {
- //A repair item is ready, therefore, return false
- return( FALSE );
- }
- else
- {
- fHaveOnlyUnRepairedItems = TRUE;
- }
- }
- }
- }
- }
- }
- return( fHaveOnlyUnRepairedItems );
- }
- UINT32 GetTimeToFixItemBeingRepaired( UINT8 ubArmsDealer, UINT16 usItemIndex, UINT8 ubElement )
- {
- //dealer must be a repair dealer
- Assert( DoesDealerDoRepairs( ubArmsDealer ) );
- // element index must be valid
- Assert( ubElement < gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubElementsAlloced );
- // that item must be active
- Assert( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].fActive );
- // that item must be in repair
- Assert( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].Info.bItemCondition < 0 );
- //if the item has already been repaired
- if( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].uiRepairDoneTime <= GetWorldTotalMin() )
- return( 0 );
- //Return how many more minutes it will take to fix the item
- return( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].uiRepairDoneTime - GetWorldTotalMin() );
- }
- BOOLEAN CanDealerTransactItem( UINT8 ubArmsDealer, UINT16 usItemIndex, BOOLEAN fPurchaseFromPlayer )
- {
- switch ( ArmsDealerInfo[ ubArmsDealer ].ubTypeOfArmsDealer )
- {
- case ARMS_DEALER_SELLS_ONLY:
- if ( fPurchaseFromPlayer )
- {
- // this dealer only sells stuff to player, so he can't buy anything from him
- return( FALSE );
- }
- break;
- case ARMS_DEALER_BUYS_ONLY:
- if ( !fPurchaseFromPlayer )
- {
- // this dealer only buys stuff from player, so he can't sell anything to him
- return( FALSE );
- }
- break;
- case ARMS_DEALER_BUYS_SELLS:
- switch ( ubArmsDealer )
- {
- case ARMS_DEALER_JAKE:
- case ARMS_DEALER_KEITH:
- case ARMS_DEALER_FRANZ:
- if ( fPurchaseFromPlayer )
- {
- // these guys will buy nearly anything from the player, regardless of what they carry for sale!
- return( CalcValueOfItemToDealer( ubArmsDealer, usItemIndex, FALSE ) > 0 );
- }
- //else selling inventory uses their inventory list
- break;
- default:
- // the others go by their inventory list
- break;
- }
- break;
- case ARMS_DEALER_REPAIRS:
- // repairmen don't have a complete list of what they'll repair in their inventory,
- // so we must check the item's properties instead.
- return( CanDealerRepairItem( ubArmsDealer, usItemIndex ) );
- default:
- AssertMsg( FALSE, String( "CanDealerTransactItem(), type of dealer %d. AM 0.", ArmsDealerInfo[ ubArmsDealer ].ubTypeOfArmsDealer ) );
- return(FALSE);
- }
- return( DoesItemAppearInDealerInventoryList( ubArmsDealer, usItemIndex, fPurchaseFromPlayer ) );
- }
- BOOLEAN CanDealerRepairItem( UINT8 ubArmsDealer, UINT16 usItemIndex )
- {
- UINT32 uiFlags;
- uiFlags = Item[ usItemIndex ].fFlags;
- // can't repair anything that's not repairable!
- if ( !( uiFlags & ITEM_REPAIRABLE ) )
- {
- return(FALSE);
- }
- switch ( ubArmsDealer )
- {
- case ARMS_DEALER_ARNIE:
- case ARMS_DEALER_PERKO:
- // repairs ANYTHING non-electronic
- if ( !( uiFlags & ITEM_ELECTRONIC ) )
- {
- return(TRUE);
- }
- break;
- case ARMS_DEALER_FREDO:
- // repairs ONLY electronics
- if ( uiFlags & ITEM_ELECTRONIC )
- {
- return(TRUE);
- }
- break;
- default:
- AssertMsg( FALSE, String( "CanDealerRepairItem(), Arms Dealer %d is not a recognized repairman!. AM 1.", ubArmsDealer ) );
- }
- // can't repair this...
- return(FALSE);
- }
- BOOLEAN AllocMemsetSpecialItemArray( DEALER_ITEM_HEADER *pDealerItem, UINT8 ubElementsNeeded )
- {
- Assert(pDealerItem);
- Assert( ubElementsNeeded > 0);
- pDealerItem->SpecialItem = MemAlloc( sizeof( DEALER_SPECIAL_ITEM ) * ubElementsNeeded );
- if( pDealerItem->SpecialItem == NULL )
- {
- Assert( 0 );
- return(FALSE);
- }
- // zero them out (they're inactive until an item is actually added)
- memset( pDealerItem->SpecialItem, 0, sizeof( DEALER_SPECIAL_ITEM ) * ubElementsNeeded );
- pDealerItem->ubElementsAlloced = ubElementsNeeded;
- return(TRUE);
- }
- BOOLEAN ResizeSpecialItemArray( DEALER_ITEM_HEADER *pDealerItem, UINT8 ubElementsNeeded )
- {
- Assert(pDealerItem);
- // must already have a ptr allocated!
- Assert(pDealerItem->SpecialItem);
-
- if ( ubElementsNeeded == pDealerItem->ubElementsAlloced)
- {
- // shouldn't have been called, but what they hey, it's not exactly a problem
- return(TRUE);
- }
- // already allocated, but change its size
- pDealerItem->SpecialItem = MemRealloc( pDealerItem->SpecialItem, sizeof( DEALER_SPECIAL_ITEM ) * ubElementsNeeded );
- if( pDealerItem->SpecialItem == NULL )
- {
- Assert( 0 );
- return(FALSE);
- }
- // if adding more elements
- if ( ubElementsNeeded > pDealerItem->ubElementsAlloced)
- {
- // zero them out (they're inactive until an item is actually added)
- memset( &(pDealerItem->SpecialItem[pDealerItem->ubElementsAlloced]), 0, sizeof( DEALER_SPECIAL_ITEM ) * ( ubElementsNeeded - pDealerItem->ubElementsAlloced) );
- }
- pDealerItem->ubElementsAlloced = ubElementsNeeded;
- return(TRUE);
- }
- void FreeSpecialItemArray( DEALER_ITEM_HEADER *pDealerItem)
- {
- Assert(pDealerItem);
- // must already have a ptr allocated!
- Assert(pDealerItem->SpecialItem);
- MemFree( pDealerItem->SpecialItem );
- pDealerItem->SpecialItem = NULL;
- pDealerItem->ubElementsAlloced = 0;
- pDealerItem->ubTotalItems = pDealerItem->ubPerfectItems;
- // doesn't effect perfect items, orders or stray bullets!
- }
- void ArmsDealerGetsFreshStock( UINT8 ubArmsDealer, UINT16 usItemIndex, UINT8 ubNumItems )
- {
- UINT8 ubCnt;
- UINT8 ubItemCondition;
- UINT8 ubPerfectOnes = 0;
- SPECIAL_ITEM_INFO SpclItemInfo;
- // create item info describing a perfect item
- SetSpecialItemInfoToDefaults( &SpclItemInfo );
- // determine the condition of each one, counting up new ones, but adding damaged ones right away
- for ( ubCnt = 0; ubCnt < ubNumItems; ubCnt++ )
- {
- ubItemCondition = DetermineDealerItemCondition( ubArmsDealer, usItemIndex);
- // if the item is brand new
- if ( ubItemCondition == 100)
- {
- ubPerfectOnes++;
- }
- else
- {
- // add a used item with that condition to his inventory
- SpclItemInfo.bItemCondition = (INT8) ubItemCondition;
- AddItemToArmsDealerInventory( ubArmsDealer, usItemIndex, &SpclItemInfo, 1 );
- }
- }
- // now add all the perfect ones, in one shot
- if ( ubPerfectOnes > 0)
- {
- SpclItemInfo.bItemCondition = 100;
- AddItemToArmsDealerInventory( ubArmsDealer, usItemIndex, &SpclItemInfo, ubPerfectOnes );
- }
- }
- UINT8 DetermineDealerItemCondition( UINT8 ubArmsDealer, UINT16 usItemIndex )
- {
- UINT8 ubCondition = 100;
- // if it's a damagable item, and not a liquid (those are always sold full)
- if ( ( Item[ usItemIndex ].fFlags & ITEM_DAMAGEABLE ) && !ItemContainsLiquid( usItemIndex ) )
- {
- // if he ONLY has used items, or 50% of the time if he carries both used & new items
- if ( ( ArmsDealerInfo[ ubArmsDealer ].uiFlags & ARMS_DEALER_ONLY_USED_ITEMS ) ||
- ( ( ArmsDealerInfo[ ubArmsDealer ].uiFlags & ARMS_DEALER_SOME_USED_ITEMS ) && ( Random( 100 ) < 50 ) ) )
- {
- // make the item a used one
- ubCondition = (UINT8)(20 + Random( 60 ));
- }
- }
- return( ubCondition);
- }
- BOOLEAN ItemContainsLiquid( UINT16 usItemIndex )
- {
- switch ( usItemIndex )
- {
- case CANTEEN:
- case BEER:
- case ALCOHOL:
- case JAR_HUMAN_BLOOD:
- case JAR_CREATURE_BLOOD:
- case JAR_QUEEN_CREATURE_BLOOD:
- case JAR_ELIXIR:
- case GAS_CAN:
- return( TRUE );
- }
- return( FALSE );
- }
- /*
- UINT32 CountTotalItemsInArmsDealersInventory( UINT8 ubArmsDealer )
- {
- UINT32 uiNumOfItems=0;
- UINT16 usItemIndex;
- //loop through all the items in this dealer's inventory
- for( usItemIndex = 1; usItemIndex < MAXITEMS; usItemIndex++ )
- {
- // This counts each pack of ammo or stacked item as one. See the "distinct" version of this for an alternate version
- uiNumOfItems += gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems;
- }
- return( uiNumOfItems );
- }
- */
- UINT32 CountDistinctItemsInArmsDealersInventory( UINT8 ubArmsDealer )
- {
- UINT32 uiNumOfItems=0;
- UINT16 usItemIndex;
- for( usItemIndex = 1; usItemIndex < MAXITEMS; usItemIndex++ )
- {
- //if there are any items
- if( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems > 0 )
- {
- // if there are any items in perfect condition
- if( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubPerfectItems > 0 )
- {
- // if the items can be stacked
- // NOTE: This test must match the one inside AddItemsToTempDealerInventory() exactly!
- if ( DealerItemIsSafeToStack( usItemIndex ) )
- {
- // regardless of how many there are, they count as 1 *distinct* item! They will all be together in one box...
- uiNumOfItems++;
- }
- else
- {
- // non-stacking items must be stored in one / box , because each may have unique fields besides bStatus[]
- // Example: guns all have ammo, ammo type, etc. We need these uniquely represented for pricing & manipulation
- uiNumOfItems += gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubPerfectItems;
- }
- }
- // each *active* special item counts as one additional distinct item (each one occupied a separate shopkeeper box!)
- // NOTE: This is including items being repaired!!!
- uiNumOfItems += CountActiveSpecialItemsInArmsDealersInventory( ubArmsDealer, usItemIndex);
- }
- }
- return( uiNumOfItems );
- }
- UINT8 CountActiveSpecialItemsInArmsDealersInventory( UINT8 ubArmsDealer, UINT16 usItemIndex )
- {
- UINT8 ubActiveSpecialItems = 0;
- UINT8 ubElement;
- // next, try to sell all the used ones, gotta do these one at a time so we can remove them by element
- for ( ubElement = 0; ubElement < gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubElementsAlloced; ubElement++ )
- {
- // don't worry about negative condition, repairmen can't come this far, they don't sell!
- if ( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].fActive )
- {
- ubActiveSpecialItems++;
- }
- }
- return( ubActiveSpecialItems );
- }
- UINT16 CountTotalItemsRepairDealerHasInForRepairs( UINT8 ubArmsDealer )
- {
- UINT16 usItemIndex;
- UINT16 usHowManyInForRepairs = 0;
- //if the dealer is not a repair dealer, no need to count, return 0
- if( !DoesDealerDoRepairs( ubArmsDealer ) )
- return( 0 );
- //loop through the dealers inventory and count the number of items in for repairs
- for( usItemIndex=0; usItemIndex < MAXITEMS; usItemIndex++ )
- {
- usHowManyInForRepairs += CountSpecificItemsRepairDealerHasInForRepairs( ubArmsDealer, usItemIndex );
- }
- return( usHowManyInForRepairs );
- }
- UINT8 CountSpecificItemsRepairDealerHasInForRepairs( UINT8 ubArmsDealer, UINT16 usItemIndex )
- {
- UINT8 ubElement;
- UINT8 ubHowManyInForRepairs = 0;
- //if the dealer is not a repair dealer, no need to count, return 0
- if( !DoesDealerDoRepairs( ubArmsDealer ) )
- return( 0 );
- //if there is some items in stock
- if( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems )
- {
- //loop through the array of items
- for( ubElement = 0; ubElement < gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubElementsAlloced; ubElement++ )
- {
- if( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].fActive)
- {
- //if the item's status is below 0, the item is being repaired
- if( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].Info.bItemCondition < 0 )
- {
- ubHowManyInForRepairs++;
- }
- }
- }
- }
- return( ubHowManyInForRepairs );
- }
- void AddObjectToArmsDealerInventory( UINT8 ubArmsDealer, OBJECTTYPE *pObject )
- {
- UINT8 ubCnt;
- SPECIAL_ITEM_INFO SpclItemInfo;
- SetSpecialItemInfoFromObject( &SpclItemInfo, pObject );
- // split up all the components of an objecttype and add them as seperate items into the dealer's inventory
- switch ( Item [ pObject->usItem ].usItemClass )
- {
- case IC_GUN:
- // add the gun (keeps the object's status and imprintID)
- // if the gun was jammed, this will forget about the jam (i.e. dealer immediately unjams anything he buys)
- AddItemToArmsDealerInventory( ubArmsDealer, pObject->usItem, &SpclItemInfo, 1 );
- // if any GunAmmoItem is specified
- if( pObject->usGunAmmoItem != NONE)
- {
- // if it's regular ammo
- if( Item[ pObject->usGunAmmoItem ].usItemClass == IC_AMMO )
- {
- // and there are some remaining
- if ( pObject->ubGunShotsLeft > 0 )
- {
- // add the bullets of its remaining ammo
- AddAmmoToArmsDealerInventory( ubArmsDealer, pObject->usGunAmmoItem, pObject->ubGunShotsLeft );
- }
- }
- else // assume it's attached ammo (mortar shells, grenades)
- {
- // add the launchable item (can't be imprinted, or have attachments!)
- SetSpecialItemInfoToDefaults( &SpclItemInfo );
- SpclItemInfo.bItemCondition = pObject->bGunAmmoStatus;
- // if the gun it was in was jammed, get rid of the negative status now
- if ( SpclItemInfo.bItemCondition < 0 )
- {
- SpclItemInfo.bItemCondition *= -1;
- }
- AddItemToArmsDealerInventory( ubArmsDealer, pObject->usGunAmmoItem, &SpclItemInfo, 1 );
- }
- }
- break;
- case IC_AMMO:
- // add the contents of each magazine (multiple mags may have vastly different #bullets left)
- for ( ubCnt = 0; ubCnt < pObject->ubNumberOfObjects; ubCnt++ )
- {
- AddAmmoToArmsDealerInventory( ubArmsDealer, pObject->usItem, pObject->ubShotsLeft[ ubCnt ] );
- }
- break;
- default:
- // add each object seperately (multiple objects may have vastly different statuses, keep any imprintID)
- for ( ubCnt = 0; ubCnt < pObject->ubNumberOfObjects; ubCnt++ )
- {
- SpclItemInfo.bItemCondition = pObject->bStatus[ ubCnt ];
- AddItemToArmsDealerInventory( ubArmsDealer, pObject->usItem, &SpclItemInfo, 1 );
- }
- break;
- }
- // loop through any detachable attachments and add them as seperate items
- for( ubCnt = 0; ubCnt < MAX_ATTACHMENTS; ubCnt++ )
- {
- if( pObject->usAttachItem[ ubCnt ] != NONE )
- {
- // ARM: Note: this is only used for selling, not repairs, so attachmentes are seperated when sold to a dealer
- // If the attachment is detachable
- if (! (Item[ pObject->usAttachItem[ubCnt] ].fFlags & ITEM_INSEPARABLE ) )
- {
- // add this particular attachment (they can't be imprinted, or themselves have attachments!)
- SetSpecialItemInfoToDefaults( &SpclItemInfo );
- SpclItemInfo.bItemCondition = pObject->bAttachStatus[ ubCnt ];
- AddItemToArmsDealerInventory( ubArmsDealer, pObject->usAttachItem[ ubCnt ], &SpclItemInfo, 1 );
- }
- }
- }
- // nuke the original object to prevent any possible item duplication
- memset( pObject, 0, sizeof( OBJECTTYPE ) );
- }
- void AddAmmoToArmsDealerInventory( UINT8 ubArmsDealer, UINT16 usItemIndex, UINT8 ubShotsLeft )
- {
- UINT8 ubMagCapacity;
- UINT8 *pubStrayAmmo;
- SPECIAL_ITEM_INFO SpclItemInfo;
- // Ammo only, please!!!
- if (Item [ usItemIndex ].usItemClass != IC_AMMO )
- {
- Assert(0);
- return;
- }
- if ( ubShotsLeft == 0)
- {
- return;
- }
- ubMagCapacity = Magazine[ Item[ usItemIndex ].ubClassIndex ].ubMagSize;
- if ( ubShotsLeft >= ubMagCapacity )
- {
- // add however many FULL magazines the #shot left represents
- SetSpecialItemInfoToDefaults( &SpclItemInfo );
- AddItemToArmsDealerInventory( ubArmsDealer, usItemIndex, &SpclItemInfo, ( UINT8 ) ( ubShotsLeft / ubMagCapacity ) );
- ubShotsLeft %= ubMagCapacity;
- }
- // any shots left now are "strays" - not enough to completely fill a magazine of this type
- if ( ubShotsLeft > 0 )
- {
- // handle "stray" ammo - add it to the dealer's stray pile
- pubStrayAmmo = &(gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubStrayAmmo);
- *pubStrayAmmo += ubShotsLeft;
- // if dealer has accumulated enough stray ammo to make another full magazine, convert it!
- if ( *pubStrayAmmo >= ubMagCapacity )
- {
- SetSpecialItemInfoToDefaults( &SpclItemInfo );
- AddItemToArmsDealerInventory( ubArmsDealer, usItemIndex, &SpclItemInfo, ( UINT8 ) ( *pubStrayAmmo / ubMagCapacity ) );
- *pubStrayAmmo = *pubStrayAmmo % ubMagCapacity;
- }
- // I know, I know, this is getting pretty anal... But what the hell, it was easy enough to do. ARM.
- }
- }
- //Use AddObjectToArmsDealerInventory() instead of this when converting a complex item in OBJECTTYPE format.
- void AddItemToArmsDealerInventory( UINT8 ubArmsDealer, UINT16 usItemIndex, SPECIAL_ITEM_INFO *pSpclItemInfo, UINT8 ubHowMany )
- {
- UINT8 ubRoomLeft;
- UINT8 ubElement;
- UINT8 ubElementsToAdd;
- BOOLEAN fFoundOne;
- BOOLEAN fSuccess;
- Assert( ubHowMany > 0);
- ubRoomLeft = 255 - gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems;
- if ( ubHowMany > ubRoomLeft)
- {
- // not enough room to store that many, any extras vanish into thin air!
- ubHowMany = ubRoomLeft;
- }
- if ( ubHowMany == 0)
- {
- return;
- }
- // decide whether this item is "special" or not
- if ( IsItemInfoSpecial( pSpclItemInfo ) )
- {
- // Anything that's used/damaged or imprinted is store as a special item in the SpecialItem array,
- // exactly one item per element. We (re)allocate memory dynamically as necessary to hold the additional items.
- do
- {
- // search for an already allocated, empty element in the special item array
- fFoundOne = FALSE;
- for ( ubElement = 0; ubElement < gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubElementsAlloced; ubElement++ )
- {
- if ( !( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].fActive ) )
- {
- //Great! Store it here, then.
- AddSpecialItemToArmsDealerInventoryAtElement( ubArmsDealer, usItemIndex, ubElement, pSpclItemInfo );
- fFoundOne = TRUE;
- break;
- }
- }
- // if we didn't find any inactive elements already allocated
- if (!fFoundOne)
- {
- // then we're going to have to allocate some more space...
- ubElementsToAdd = max( SPECIAL_ITEMS_ALLOCED_AT_ONCE, ubHowMany);
- // if there aren't any allocated at all right now
- if ( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubElementsAlloced == 0 )
- {
- // allocate new memory for the real buffer
- fSuccess = AllocMemsetSpecialItemArray( &gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ], ubElementsToAdd );
- }
- else
- {
- // we have some allocated, but they're all full and we need more. MemRealloc existing amount + # addition elements
- fSuccess = ResizeSpecialItemArray( &gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ], (UINT8)( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubElementsAlloced + ubElementsToAdd ) );
- }
- if ( !fSuccess )
- {
- return;
- }
- // now add the special item at the first of the newly added elements (still stored in ubElement!)
- AddSpecialItemToArmsDealerInventoryAtElement( ubArmsDealer, usItemIndex, ubElement, pSpclItemInfo );
- }
- // store the # of the element it was placed in globally so anyone who needs that can grab it there
- gubLastSpecialItemAddedAtElement = ubElement;
- ubHowMany--;
- } while ( ubHowMany > 0);
- }
- else // adding perfect item(s)
- {
- // then it's stored as a "perfect" item, simply add it to that counter!
- gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubPerfectItems += ubHowMany;
- // increase total items of this type
- gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems += ubHowMany;
- }
- }
- void AddSpecialItemToArmsDealerInventoryAtElement( UINT8 ubArmsDealer, UINT16 usItemIndex, UINT8 ubElement, SPECIAL_ITEM_INFO *pSpclItemInfo )
- {
- Assert( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems < 255 );
- Assert( ubElement < gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubElementsAlloced );
- Assert( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].fActive == FALSE );
- Assert( IsItemInfoSpecial( pSpclItemInfo ) );
- //Store the special values in that element, and make it active
- gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].fActive = TRUE;
- memcpy( &(gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].Info), pSpclItemInfo, sizeof( SPECIAL_ITEM_INFO ) );
- // increase the total items
- gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems++;
- }
- // removes ubHowMany items of usItemIndex with the matching Info from dealer ubArmsDealer
- void RemoveItemFromArmsDealerInventory( UINT8 ubArmsDealer, UINT16 usItemIndex, SPECIAL_ITEM_INFO *pSpclItemInfo, UINT8 ubHowMany )
- {
- DEALER_SPECIAL_ITEM *pSpecialItem;
- UINT8 ubElement;
- Assert( ubHowMany <= gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems );
- if ( ubHowMany == 0)
- {
- return;
- }
- // decide whether this item is "special" or not
- if ( IsItemInfoSpecial( pSpclItemInfo ) )
- {
- // look through the elements, trying to find special items matching the specifications
- for ( ubElement = 0; ubElement < gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubElementsAlloced; ubElement++ )
- {
- pSpecialItem = &(gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ]);
- // if this element is in use
- if ( pSpecialItem->fActive )
- {
- // and its contents are exactly what we're looking for
- if( memcmp( &(gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].Info), pSpclItemInfo, sizeof( SPECIAL_ITEM_INFO ) ) == 0 )
- {
- // Got one! Remove it
- RemoveSpecialItemFromArmsDealerInventoryAtElement( ubArmsDealer, usItemIndex, ubElement );
- ubHowMany--;
- if ( ubHowMany == 0)
- {
- break;
- }
- }
- }
- }
- // when we've searched all the special item elements, we'd better not have any more items to remove!
- Assert( ubHowMany == 0);
- }
- else // removing perfect item(s)
- {
- // then it's stored as a "perfect" item, simply subtract from tha counter!
- Assert( ubHowMany <= gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubPerfectItems );
- gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubPerfectItems -= ubHowMany;
- // decrease total items of this type
- gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems -= ubHowMany;
- }
- }
- void RemoveRandomItemFromArmsDealerInventory( UINT8 ubArmsDealer, UINT16 usItemIndex, UINT8 ubHowMany )
- {
- UINT8 ubWhichOne;
- UINT8 ubSkippedAlready;
- BOOLEAN fFoundIt;
- UINT8 ubElement;
- SPECIAL_ITEM_INFO SpclItemInfo;
- // not permitted for repair dealers - would take extra code to subtract items under repair from ubTotalItems!!!
- Assert( !DoesDealerDoRepairs( ubArmsDealer ) );
- // Can't remove any items in for repair, though!
- Assert( ubHowMany <= gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems );
- while ( ubHowMany > 0)
- {
- // pick a random one to get rid of
- ubWhichOne = (UINT8)Random(gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems );
- // if we picked one of the perfect ones...
- if ( ubWhichOne < gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubPerfectItems )
- {
- // create item info describing a perfect item
- SetSpecialItemInfoToDefaults( &SpclItemInfo );
- // then that's easy, its condition is 100, so remove one of those
- RemoveItemFromArmsDealerInventory( ubArmsDealer, usItemIndex, &SpclItemInfo, 1 );
- }
- else
- {
- // Yikes! Gotta look through the special items. We already know it's not any of the perfect ones, subtract those
- ubWhichOne -= gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubPerfectItems;
- ubSkippedAlready = 0;
- fFoundIt = FALSE;
- for ( ubElement = 0; ubElement < gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubElementsAlloced; ubElement++ )
- {
- // if this is an active special item, not in repair
- if ( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].fActive ) // &&
- // ( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].Info.bItemCondition > 0 ) )
- {
- // if we skipped the right amount of them
- if ( ubSkippedAlready == ubWhichOne )
- {
- // then this one is it! That's the one we're gonna remove
- RemoveSpecialItemFromArmsDealerInventoryAtElement( ubArmsDealer, usItemIndex, ubElement );
- fFoundIt = TRUE;
- break;
- }
- else
- {
- // keep looking...
- ubSkippedAlready++;
- }
- }
- }
-
- // this HAS to work, or the data structure is corrupt!
- Assert(fFoundIt);
- }
- ubHowMany--;
- }
- }
- void RemoveSpecialItemFromArmsDealerInventoryAtElement( UINT8 ubArmsDealer, UINT16 usItemIndex, UINT8 ubElement )
- {
- Assert( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems > 0 );
- Assert( ubElement < gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubElementsAlloced );
- Assert( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].fActive == TRUE );
- // wipe it out (turning off fActive)
- memset( &( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ] ), 0, sizeof( DEALER_SPECIAL_ITEM ) );
- // one fewer item remains...
- gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems--;
- }
- BOOLEAN AddDeadArmsDealerItemsToWorld( UINT8 ubMercID )
- {
- INT8 bArmsDealer;
- SOLDIERTYPE *pSoldier;
- UINT16 usItemIndex;
- UINT8 ubElement;
- UINT8 ubHowManyMaxAtATime;
- UINT8 ubLeftToDrop;
- UINT8 ubNowDropping;
- OBJECTTYPE TempObject;
- DEALER_SPECIAL_ITEM *pSpecialItem;
- SPECIAL_ITEM_INFO SpclItemInfo;
- //Get Dealer ID from from merc Id
- bArmsDealer = GetArmsDealerIDFromMercID( ubMercID );
- if( bArmsDealer == -1 )
- {
- // not a dealer, that's ok, we get called for every dude that croaks.
- return( FALSE );
- }
- // mark the dealer as being out of business!
- gArmsDealerStatus[ bArmsDealer ].fOutOfBusiness = TRUE;
- //Get a pointer to the dealer
- pSoldier = FindSoldierByProfileID( ubMercID, FALSE );
- if( pSoldier == NULL )
- {
- // This should never happen, a dealer getting knocked off without the sector being loaded, should it?
- // If it's possible, we should modify code below to dump his belongings into the sector without using pSoldier->sGridNo
- Assert(0);
- return( FALSE );
- }
- //loop through all the items in the dealer's inventory, and drop them all where the dealer was set up.
- for( usItemIndex = 1; usItemIndex < MAXITEMS; usItemIndex++ )
- {
- //if the dealer has any items of this type
- if( gArmsDealersInventory[ bArmsDealer ][ usItemIndex ].ubTotalItems > 0)
- {
- // if he has any perfect items of this time
- if ( gArmsDealersInventory[ bArmsDealer ][ usItemIndex ].ubPerfectItems > 0 )
- {
- // drop all the perfect items first
- // drop stackable items like ammo in stacks of whatever will fit into a large pocket instead of one at a time
- ubHowManyMaxAtATime = ItemSlotLimit( usItemIndex, BIGPOCK1POS );
- if ( ubHowManyMaxAtATime < 1 )
- {
- ubHowManyMaxAtATime = 1;
- }
- // create item info describing a perfect item
- SetSpecialItemInfoToDefaults( &SpclItemInfo );
- ubLeftToDrop = gArmsDealersInventory[ bArmsDealer ][ usItemIndex ].ubPerfectItems;
- // ATE: While it IS leagal here to use pSoldier->sInitialGridNo, cause of where this
- // function is called, there are times when we're not guarenteed that sGridNo is good
- while ( ubLeftToDrop > 0)
- {
- ubNowDropping = min( ubLeftToDrop, ubHowManyMaxAtATime );
- MakeObjectOutOfDealerItems( usItemIndex, &SpclItemInfo, &TempObject, ubNowDropping );
- AddItemToPool( pSoldier->sInitialGridNo, &TempObject, INVISIBLE, 0, 0, 0 );
-
- ubLeftToDrop -= ubNowDropping;
- }
- // remove them all from his inventory
- RemoveItemFromArmsDealerInventory( bArmsDealer, usItemIndex, &SpclItemInfo, gArmsDealersInventory[ bArmsDealer ][ usItemIndex ].ubPerfectItems );
- }
- // then drop all the special items
- for ( ubElement = 0; ubElement < gArmsDealersInventory[ bArmsDealer ][ usItemIndex ].ubElementsAlloced; ubElement++ )
- {
- pSpecialItem = &(gArmsDealersInventory[ bArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ]);
- if ( pSpecialItem->fActive )
- {
- MakeObjectOutOfDealerItems(usItemIndex, &(pSpecialItem->Info), &TempObject, 1 );
- AddItemToPool( pSoldier->sInitialGridNo, &TempObject, INVISIBLE, 0, 0, 0 );
- RemoveItemFromArmsDealerInventory( bArmsDealer, usItemIndex, &(pSpecialItem->Info), 1 );
- }
- }
- // release any memory allocated for special items, he won't need it now...
- if( gArmsDealersInventory[ bArmsDealer ][ usItemIndex ].ubElementsAlloced > 0 )
- {
- FreeSpecialItemArray( &gArmsDealersInventory[ bArmsDealer ][ usItemIndex ] );
- }
- }
- }
- //if the dealer has money
- if( gArmsDealerStatus[ bArmsDealer ].uiArmsDealersCash > 0 )
- {
- //Create the object
- memset( &TempObject, 0, sizeof( OBJECTTYPE ) );
- if( !CreateMoney( gArmsDealerStatus[ bArmsDealer ].uiArmsDealersCash, &TempObject ) )
- {
- return( FALSE );
- }
- //add the money item to the dealers feet
- AddItemToPool( pSoldier->sInitialGridNo, &TempObject, INVISIBLE, 0, 0, 0 );
- gArmsDealerStatus[ bArmsDealer ].uiArmsDealersCash = 0;
- }
- return( TRUE );
- }
- void MakeObjectOutOfDealerItems( UINT16 usItemIndex, SPECIAL_ITEM_INFO *pSpclItemInfo, OBJECTTYPE *pObject, UINT8 ubHowMany )
- {
- INT8 bItemCondition;
- UINT8 ubCnt;
- bItemCondition = pSpclItemInfo->bItemCondition;
- //if the item condition is below 0, the item is in for repairs, so flip the sign
- if( bItemCondition < 0 )
- {
- bItemCondition *= -1;
- }
- memset( pObject, 0, sizeof( OBJECTTYPE ) );
- //Create the item object
- CreateItems( usItemIndex, bItemCondition, ubHowMany, pObject );
- // set the ImprintID
- pObject->ubImprintID = pSpclItemInfo->ubImprintID;
- // add any attachments we've been storing
- for ( ubCnt = 0; ubCnt < MAX_ATTACHMENTS; ubCnt++ )
- {
- if ( pSpclItemInfo->usAttachment[ ubCnt ] != NONE )
- {
- // store what it is, and its condition
- pObject->usAttachItem[ ubCnt ] = pSpclItemInfo->usAttachment[ ubCnt ];
- pObject->bAttachStatus[ ubCnt ] = pSpclItemInfo->bAttachmentStatus[ ubCnt ];
- }
- }
- // if it's a gun
- if (Item [ pObject->usItem ].usItemClass == IC_GUN )
- {
- // Empty out the bullets put in by CreateItem(). We now sell all guns empty of bullets. This is so that we don't
- // have to keep track of #bullets in a gun throughout dealer inventory. Without this, players could "reload" guns
- // they don't have ammo for by selling them to Tony & buying them right back fully loaded! One could repeat this
- // ad nauseum (empty the gun between visits) as a (really expensive) way to get unlimited special ammo like rockets.
- pObject->ubGunShotsLeft = 0;
- }
- }
- void GiveObjectToArmsDealerForRepair( UINT8 ubArmsDealer, OBJECTTYPE *pObject, UINT8 ubOwnerProfileId )
- {
- // UINT8 ubCnt;
- SPECIAL_ITEM_INFO SpclItemInfo;
- Assert( DoesDealerDoRepairs( ubArmsDealer ) );
- // Any object passed into here must already be:
- // a) Unstacked
- Assert( pObject->ubNumberOfObjects == 1 );
- // b) Repairable
- Assert( CanDealerRepairItem( ubArmsDealer, pObject->usItem ) );
- // c) Actually damaged, or a rocket rifle (being reset)
- Assert( ( pObject->bStatus[ 0 ] < 100 ) || ItemIsARocketRifle( pObject->usItem ) );
- /* ARM: Can now repair with removeable attachments still attached...
- // d) Already stripped of all *detachable* attachments
- for( ubCnt = 0; ubCnt < MAX_ATTACHMENTS; ubCnt++ )
- {
- if ( pObject->usAttachItem[ ubCnt ] != NONE )
- {
- // If the attachment is detachable
- if (! (Item[ pObject->usAttachItem[ubCnt] ].fFlags & ITEM_INSEPARABLE ) )
- {
- Assert( 0 );
- }
- }
- }
- */
- // e) If a gun, stripped of any non-ammo-class GunAmmoItems, and bullets
- if (Item [ pObject->usItem ].usItemClass == IC_GUN )
- {
- // if any GunAmmoItem is specified
- if( pObject->usGunAmmoItem != NONE)
- {
- // it better be regular ammo, and empty
- Assert( Item[ pObject->usGunAmmoItem ].usItemClass == IC_AMMO );
- Assert( pObject->ubGunShotsLeft == 0 );
- }
- }
- SetSpecialItemInfoFromObject( &SpclItemInfo, pObject );
- // ok, given all that, now everything is easy!
- // if the gun was jammed, this will forget about the jam (i.e. dealer immediately unjams anything he will be repairing)
- GiveItemToArmsDealerforRepair( ubArmsDealer, pObject->usItem, &SpclItemInfo, ubOwnerProfileId );
- }
- //PLEASE: Use GiveObjectToArmsDealerForRepair() instead of this when repairing a item in OBJECTTYPE format.
- void GiveItemToArmsDealerforRepair( UINT8 ubArmsDealer, UINT16 usItemIndex, SPECIAL_ITEM_INFO *pSpclItemInfo, UINT8 ubOwnerProfileId )
- {
- UINT32 uiTimeWhenFreeToStartIt;
- UINT32 uiMinutesToFix;
- UINT32 uiMinutesShopClosedBeforeItsDone;
- UINT32 uiDoneWhen;
- Assert( DoesDealerDoRepairs( ubArmsDealer ) );
- Assert( pSpclItemInfo->bItemCondition > 0 );
- Assert( ( pSpclItemInfo->bItemCondition < 100 ) || ItemIsARocketRifle( usItemIndex ) );
- // figure out the earliest the repairman will be free to start repairing this item
- uiTimeWhenFreeToStartIt = WhenWillRepairmanBeAllDoneRepairing( ubArmsDealer );
- //Determine how long it will take to fix
- uiMinutesToFix = CalculateSpecialItemRepairTime( ubArmsDealer, usItemIndex, pSpclItemInfo );
- uiMinutesShopClosedBeforeItsDone = CalculateOvernightRepairDelay( ubArmsDealer, uiTimeWhenFreeToStartIt, uiMinutesToFix );
- // clock time when this will finally be ready
- uiDoneWhen = uiTimeWhenFreeToStartIt + uiMinutesToFix + uiMinutesShopClosedBeforeItsDone;
- // Negate the status
- pSpclItemInfo->bItemCondition *= -1;
- // give it to the dealer
- AddItemToArmsDealerInventory( ubArmsDealer, usItemIndex, pSpclItemInfo, 1 );
- //Set the time at which item will be fixed
- gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ gubLastSpecialItemAddedAtElement ].uiRepairDoneTime = uiDoneWhen;
- //Remember the original owner of the item
- gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ gubLastSpecialItemAddedAtElement ].ubOwnerProfileId = ubOwnerProfileId;
- }
- UINT32 WhenWillRepairmanBeAllDoneRepairing( UINT8 ubArmsDealer )
- {
- UINT32 uiWhenFree;
- UINT16 usItemIndex;
- UINT8 ubElement;
- Assert( DoesDealerDoRepairs( ubArmsDealer ) );
- // if nothing is in for repairs, he'll be free RIGHT NOW!
- uiWhenFree = GetWorldTotalMin();
- //loop through the dealers inventory
- for( usItemIndex = 1; usItemIndex < MAXITEMS; usItemIndex++ )
- {
- //if there is some items in stock
- if( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubTotalItems > 0 )
- {
- for ( ubElement = 0; ubElement < gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubElementsAlloced; ubElement++ )
- {
- if ( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].fActive )
- {
- //if the item is in for repairs
- if( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].Info.bItemCondition < 0 )
- {
- // if this item will be done later than the latest we've found so far
- if ( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].uiRepairDoneTime > uiWhenFree )
- {
- // then we're busy til then!
- uiWhenFree = gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].uiRepairDoneTime;
- }
- }
- }
- }
- }
- }
- return( uiWhenFree );
- }
- UINT32 CalculateSpecialItemRepairTime( UINT8 ubArmsDealer, UINT16 usItemIndex, SPECIAL_ITEM_INFO *pSpclItemInfo )
- {
- UINT32 uiRepairTime;
- UINT8 ubCnt;
- uiRepairTime = CalculateSimpleItemRepairTime( ubArmsDealer, usItemIndex, pSpclItemInfo->bItemCondition );
- // add time to repair any attachments on it
- for ( ubCnt = 0; ubCnt < MAX_ATTACHMENTS; ubCnt++ )
- {
- if ( pSpclItemInfo->usAttachment[ ubCnt ] != NONE )
- {
- // if damaged and repairable
- if ( ( pSpclItemInfo->bAttachmentStatus[ ubCnt ] < 100 ) && CanDealerRepairItem( ubArmsDealer, pSpclItemInfo->usAttachment[ ubCnt ] ) )
- {
- uiRepairTime += CalculateSimpleItemRepairTime( ubArmsDealer, pSpclItemInfo->usAttachment[ ubCnt ], pSpclItemInfo->bAttachmentStatus[ ubCnt ] );
- }
- }
- }
- return( uiRepairTime );
- }
- UINT32 CalculateObjectItemRepairTime( UINT8 ubArmsDealer, OBJECTTYPE *pItemObject )
- {
- UINT32 uiRepairTime;
- UINT8 ubCnt;
- uiRepairTime = CalculateSimpleItemRepairTime( ubArmsDealer, pItemObject->usItem, pItemObject->bStatus[ 0 ] );
- // add time to repair any attachments on it
- for ( ubCnt = 0; ubCnt < MAX_ATTACHMENTS; ubCnt++ )
- {
- if ( pItemObject->usAttachItem[ ubCnt ] != NONE )
- {
- // if damaged and repairable
- if ( ( pItemObject->bAttachStatus[ ubCnt ] < 100 ) && CanDealerRepairItem( ubArmsDealer, pItemObject->usAttachItem[ ubCnt ] ) )
- {
- uiRepairTime += CalculateSimpleItemRepairTime( ubArmsDealer, pItemObject->usAttachItem[ ubCnt ], pItemObject->bAttachStatus[ ubCnt ] );
- }
- }
- }
- return( uiRepairTime );
- }
- UINT32 CalculateSimpleItemRepairTime( UINT8 ubArmsDealer, UINT16 usItemIndex, INT8 bItemCondition )
- {
- UINT32 uiTimeToRepair = 0;
- UINT32 uiRepairCost = 0;
- Assert( DoesDealerDoRepairs( ubArmsDealer ) );
- // first calc what he'll charge - that takes care of item condition, repair ease, and his repair cost "markup"
- uiRepairCost = CalculateSimpleItemRepairCost( ubArmsDealer, usItemIndex, bItemCondition );
- // Now adjust that for the repairman's individual repair speed.
- // For a repairman, his BUY modifier controls his REPAIR SPEED (1.0 means minutes to repair = price in $)
- // with a REPAIR SPEED of 1.0, typical gun price of $2000, and a REPAIR COST of 0.5 this works out to 16.6 hrs
- // for a full 100% status repair... Not bad.
- uiTimeToRepair = (UINT32)( uiRepairCost * ArmsDealerInfo[ ubArmsDealer ].dRepairSpeed );
- // repairs on electronic items take twice as long if the guy doesn't have the skill
- // for dealers, this means anyone but Fredo the Electronics guy takes twice as long (but doesn't charge double)
- // (Mind you, current he's the ONLY one who CAN repair Electronics at all! Oh well.)
- if( ( Item[ usItemIndex ].fFlags & ITEM_ELECTRONIC ) && ( ubArmsDealer != ARMS_DEALER_FREDO ) )
- {
- uiTimeToRepair *= 2;
- }
- // avoid "instant" repairs on really cheap, barely damaged crap...
- if (uiTimeToRepair < MIN_REPAIR_TIME_IN_MINUTES)
- {
- uiTimeToRepair = MIN_REPAIR_TIME_IN_MINUTES;
- }
- return( uiTimeToRepair );
- }
- UINT32 CalculateSpecialItemRepairCost( UINT8 ubArmsDealer, UINT16 usItemIndex, SPECIAL_ITEM_INFO *pSpclItemInfo )
- {
- UINT32 uiRepairCost;
- UINT8 ubCnt;
- uiRepairCost = CalculateSimpleItemRepairCost( ubArmsDealer, usItemIndex, pSpclItemInfo->bItemCondition );
- // add cost of repairing any attachments on it
- for ( ubCnt = 0; ubCnt < MAX_ATTACHMENTS; ubCnt++ )
- {
- if ( pSpclItemInfo->usAttachment[ ubCnt ] != NONE )
- {
- // if damaged and repairable
- if ( ( pSpclItemInfo->bAttachmentStatus[ ubCnt ] < 100 ) && CanDealerRepairItem( ubArmsDealer, pSpclItemInfo->usAttachment[ ubCnt ] ) )
- {
- uiRepairCost += CalculateSimpleItemRepairCost( ubArmsDealer, pSpclItemInfo->usAttachment[ ubCnt ], pSpclItemInfo->bAttachmentStatus[ ubCnt ] );
- }
- }
- }
- return( uiRepairCost );
- }
- UINT32 CalculateObjectItemRepairCost( UINT8 ubArmsDealer, OBJECTTYPE *pItemObject )
- {
- UINT32 uiRepairCost;
- UINT8 ubCnt;
- uiRepairCost = CalculateSimpleItemRepairCost( ubArmsDealer, pItemObject->usItem, pItemObject->bStatus[ 0 ] );
- // add cost of repairing any attachments on it
- for ( ubCnt = 0; ubCnt < MAX_ATTACHMENTS; ubCnt++ )
- {
- if ( pItemObject->usAttachItem[ ubCnt ] != NONE )
- {
- // if damaged and repairable
- if ( ( pItemObject->bAttachStatus[ ubCnt ] < 100 ) && CanDealerRepairItem( ubArmsDealer, pItemObject->usAttachItem[ ubCnt ] ) )
- {
- uiRepairCost += CalculateSimpleItemRepairCost( ubArmsDealer, pItemObject->usAttachItem[ ubCnt ], pItemObject->bAttachStatus[ ubCnt ] );
- }
- }
- }
- return( uiRepairCost );
- }
- UINT32 CalculateSimpleItemRepairCost( UINT8 ubArmsDealer, UINT16 usItemIndex, INT8 bItemCondition )
- {
- UINT32 uiItemCost = 0;
- UINT32 uiRepairCost = 0;
- INT16 sRepairCostAdj = 0;
- // UINT32 uiDifFrom10=0;
- // figure out the full value of the item, modified by this dealer's personal Sell (i.e. repair cost) modifier
- // don't use CalcShopKeeperItemPrice - we want FULL value!!!
- uiItemCost = (UINT32)(( Item[ usItemIndex ].usPrice * ArmsDealerInfo[ ubArmsDealer ].dRepairCost ) );
- // get item's repair ease, for each + point is 10% easier, each - point is 10% harder to repair
- sRepairCostAdj = 100 - ( 10 * Item[ usItemIndex ].bRepairEase );
- // make sure it ain't somehow gone too low!
- if (sRepairCostAdj < 10)
- {
- sRepairCostAdj = 10;
- }
- // calculate repair cost, the more broken it is the more it costs, and the difficulty of repair it is also a factor
- uiRepairCost = (UINT32)( uiItemCost * ( sRepairCostAdj * (100 - bItemCondition) / ((FLOAT)100 * 100) ));
- /*
- //if the price is not diviseble by 10, make it so
- uiDifFrom10 = 10 - uiRepairCost % 10;
- if( uiDifFrom10 != 0 )
- {
- uiRepairCost += uiDifFrom10;
- }
- */
- if ( ItemIsARocketRifle( usItemIndex ) )
- {
- // resetting imprinting for a rocket rifle costs something extra even if rifle is at 100%
- uiRepairCost += 100;
- }
- // anything repairable has to have a minimum price
- if ( uiRepairCost < MIN_REPAIR_COST )
- {
- uiRepairCost = MIN_REPAIR_COST;
- }
- return( uiRepairCost );
- }
- void SetSpecialItemInfoToDefaults( SPECIAL_ITEM_INFO *pSpclItemInfo )
- {
- UINT8 ubCnt;
- memset( pSpclItemInfo, 0, sizeof( SPECIAL_ITEM_INFO ) );
- pSpclItemInfo->bItemCondition = 100;
- pSpclItemInfo->ubImprintID = NO_PROFILE;
- for ( ubCnt = 0; ubCnt < MAX_ATTACHMENTS; ubCnt++ )
- {
- pSpclItemInfo->usAttachment[ ubCnt ] = NONE;
- pSpclItemInfo->bAttachmentStatus[ ubCnt ] = 0;
- }
- }
- void SetSpecialItemInfoFromObject( SPECIAL_ITEM_INFO *pSpclItemInfo, OBJECTTYPE *pObject )
- {
- UINT8 ubCnt;
- memset(pSpclItemInfo, 0, sizeof( SPECIAL_ITEM_INFO ) );
- if( Item[ pObject->usItem ].usItemClass == IC_AMMO )
- {
- // ammo condition is always 100, don't use status, which holds the #bullets
- pSpclItemInfo->bItemCondition = 100;
- }
- else
- {
- pSpclItemInfo->bItemCondition = pObject->bStatus[ 0 ];
- }
- // only guns currently have imprintID properly initialized...
- if ( Item[ pObject->usItem ].usItemClass == IC_GUN)
- {
- pSpclItemInfo->ubImprintID = pObject->ubImprintID;
- }
- else
- {
- // override garbage imprintIDs (generally 0) for non-guns
- pSpclItemInfo->ubImprintID = NO_PROFILE;
- }
- for ( ubCnt = 0; ubCnt < MAX_ATTACHMENTS; ubCnt++ )
- {
- if( pObject->usAttachItem[ ubCnt ] != NONE )
- {
- // store what it is
- pSpclItemInfo->usAttachment[ ubCnt ] = pObject->usAttachItem[ ubCnt ];
- pSpclItemInfo->bAttachmentStatus[ ubCnt ] = pObject->bAttachStatus[ ubCnt ];
- }
- else
- {
- pSpclItemInfo->usAttachment[ ubCnt ] = NONE;
- pSpclItemInfo->bAttachmentStatus[ ubCnt ] = 0;
- }
- }
- }
- BOOLEAN IsItemInfoSpecial( SPECIAL_ITEM_INFO *pSpclItemInfo )
- {
- UINT8 ubCnt;
- // being damaged / in repairs makes an item special
- if ( pSpclItemInfo->bItemCondition != 100 )
- {
- return(TRUE);
- }
- // being imprinted makes an item special
- if (pSpclItemInfo->ubImprintID != NO_PROFILE)
- {
- return(TRUE);
- }
- // having an attachment makes an item special
- for ( ubCnt = 0; ubCnt < MAX_ATTACHMENTS; ubCnt++ )
- {
- if ( pSpclItemInfo->usAttachment[ ubCnt ] != NONE )
- {
- return(TRUE);
- }
- }
- // otherwise, it's just a "perfect" item, nothing special about it
- return(FALSE);
- }
- BOOLEAN DoesItemAppearInDealerInventoryList( UINT8 ubArmsDealer, UINT16 usItemIndex, BOOLEAN fPurchaseFromPlayer )
- {
- DEALER_POSSIBLE_INV *pDealerInv=NULL;
- UINT16 usCnt;
- // the others will buy only things that appear in their own "for sale" inventory lists
- pDealerInv = GetPointerToDealersPossibleInventory( ubArmsDealer );
- Assert( pDealerInv != NULL );
- // loop through the dealers' possible inventory and see if the item exists there
- usCnt = 0;
- while( pDealerInv[ usCnt ].sItemIndex != LAST_DEALER_ITEM )
- {
- //if the initial dealer inv contains the required item, the dealer can sell the item
- if( pDealerInv[ usCnt ].sItemIndex == usItemIndex )
- {
- // if optimal quantity listed is 0, it means dealer won't sell it himself, but will buy it from the player!
- if ( ( pDealerInv[ usCnt ].ubOptimalNumber > 0 ) || fPurchaseFromPlayer )
- {
- return( TRUE );
- }
- }
- usCnt++;
- }
- return( FALSE );
- }
- UINT16 CalcValueOfItemToDealer( UINT8 ubArmsDealer, UINT16 usItemIndex, BOOLEAN fDealerSelling )
- {
- UINT16 usBasePrice;
- UINT8 ubItemPriceClass;
- UINT8 ubDealerPriceClass;
- UINT16 usValueToThisDealer;
- usBasePrice = Item[ usItemIndex ].usPrice;
- if ( usBasePrice == 0 )
- {
- // worthless to any dealer
- return( 0 );
- }
- // figure out the price class this dealer prefers
- switch ( ubArmsDealer )
- {
- case ARMS_DEALER_JAKE:
- ubDealerPriceClass = PRICE_CLASS_JUNK;
- break;
- case ARMS_DEALER_KEITH:
- ubDealerPriceClass = PRICE_CLASS_CHEAP;
- break;
- case ARMS_DEALER_FRANZ:
- ubDealerPriceClass = PRICE_CLASS_EXPENSIVE;
- break;
- // other dealers don't use this system
- default:
- if ( DoesItemAppearInDealerInventoryList( ubArmsDealer, usItemIndex, TRUE ) )
- {
- return( usBasePrice );
- }
- else
- {
- return( 0 );
- }
- }
- // the rest of this function applies only to the "general" dealers ( Jake, Keith, and Franz )
- // Micky & Gabby specialize in creature parts & such, the others don't buy these at all (exception: jars)
- if ( ( usItemIndex != JAR ) &&
- ( DoesItemAppearInDealerInventoryList( ARMS_DEALER_MICKY, usItemIndex, TRUE ) ||
- DoesItemAppearInDealerInventoryList( ARMS_DEALER_GABBY, usItemIndex, TRUE ) ) )
- {
- return( 0 );
- }
- if ( ( ubArmsDealer == ARMS_DEALER_KEITH ) && ( Item [ usItemIndex].usItemClass & ( IC_GUN | IC_LAUNCHER ) ) )
- {
- // Keith won't buy guns until the Hillbillies are vanquished
- if( CheckFact( FACT_HILLBILLIES_KILLED, KEITH ) == FALSE )
- {
- return( 0 );
- }
- }
- // figure out which price class it belongs to
- if ( usBasePrice < 100 )
- {
- ubItemPriceClass = PRICE_CLASS_JUNK;
- }
- else
- if ( usBasePrice < 1000 )
- {
- ubItemPriceClass = PRICE_CLASS_CHEAP;
- }
- else
- {
- ubItemPriceClass = PRICE_CLASS_EXPENSIVE;
- }
- if( !fDealerSelling )
- {
- // junk dealer won't buy expensive stuff at all, expensive dealer won't buy junk at all
- if ( abs( (INT8) ubDealerPriceClass - (INT8) ubItemPriceClass ) == 2 )
- {
- return( 0 );
- }
- }
- // start with the base price
- usValueToThisDealer = usBasePrice;
- // if it's out of their preferred price class
- if ( ubDealerPriceClass != ubItemPriceClass )
- {
- // exception: Gas (Jake's)
- if ( usItemIndex != GAS_CAN )
- {
- // they pay only 1/3 of true value!
- usValueToThisDealer /= 3;
- }
- }
- #ifndef JA2DEMO // don't halve the gun/silencer prices in the demo...
- // Tony specializes in guns, weapons, and ammo, so make others pay much less for that kind of stuff
- if ( DoesItemAppearInDealerInventoryList( ARMS_DEALER_TONY, usItemIndex, TRUE ) )
- {
- // others pay only 1/2 of that value!
- usValueToThisDealer /= 2;
- }
- #endif
- // minimum bet $1 !
- if ( usValueToThisDealer == 0 )
- {
- usValueToThisDealer = 1;
- }
- return( usValueToThisDealer );
- }
- // this only exists to support saves made with game versions < 54 or 55!
- BOOLEAN LoadIncompleteArmsDealersStatus( HWFILE hFile, BOOLEAN fIncludesElgin, BOOLEAN fIncludesManny )
- {
- UINT32 uiDealersSaved;
- UINT32 uiNumBytesRead;
- Assert( !fIncludesElgin || !fIncludesManny );
- if ( !fIncludesElgin )
- {
- // read 2 fewer element without Elgin or Manny in there...
- uiDealersSaved = NUM_ARMS_DEALERS - 2;
- }
- else
- {
- // read one fewer element without Elgin in there...
- uiDealersSaved = NUM_ARMS_DEALERS - 1;
- }
- // read in all other dealer's status
- if (!FileRead( hFile, gArmsDealerStatus, uiDealersSaved * sizeof( ARMS_DEALER_STATUS ), &uiNumBytesRead ))
- {
- return( FALSE );
- }
- // read in all other dealer's inventory
- if (!FileRead( hFile, gArmsDealersInventory, uiDealersSaved * sizeof( DEALER_ITEM_HEADER ) * MAXITEMS, &uiNumBytesRead ))
- {
- return( FALSE );
- }
- if ( !fIncludesElgin )
- {
- // initialize Elgin now...
- InitializeOneArmsDealer( ARMS_DEALER_ELGIN );
- }
- if ( !fIncludesManny )
- {
- // initialize Manny now...
- InitializeOneArmsDealer( ARMS_DEALER_MANNY );
- }
- return(TRUE);
- }
- BOOLEAN DealerItemIsSafeToStack( UINT16 usItemIndex )
- {
- // basically any item type with nothing unique about it besides its status can be stacked in dealer's inventory boxes...
- // NOTE: This test is only applied to items already KNOWN to be perfect - special items are obviously not-stackable
- if ( Item[ usItemIndex ].usItemClass == IC_GUN )
- {
- return( FALSE );
- }
- /*
- if ( ItemSlotLimit( usItemIndex, BIGPOCK1POS ) > 1 )
- {
- return( TRUE );
- }
- */
- return( TRUE );
- }
- void GuaranteeMinimumAlcohol( UINT8 ubArmsDealer )
- {
- GuaranteeAtLeastXItemsOfIndex( ubArmsDealer, BEER, ( UINT8 ) ( GetDealersMaxItemAmount( ubArmsDealer, BEER ) / 3 ) );
- GuaranteeAtLeastXItemsOfIndex( ubArmsDealer, WINE, ( UINT8 ) ( GetDealersMaxItemAmount( ubArmsDealer, WINE ) / 3 ) );
- GuaranteeAtLeastXItemsOfIndex( ubArmsDealer, ALCOHOL, ( UINT8 ) ( GetDealersMaxItemAmount( ubArmsDealer, ALCOHOL ) / 3 ) );
- }
- BOOLEAN ItemIsARocketRifle( INT16 sItemIndex )
- {
- if ( ( sItemIndex == ROCKET_RIFLE ) || ( sItemIndex == AUTO_ROCKET_RIFLE ) )
- {
- return( TRUE );
- }
- else
- {
- return( FALSE );
- }
- }
- BOOLEAN GetArmsDealerShopHours( UINT8 ubArmsDealer, UINT32 *puiOpeningTime, UINT32 *puiClosingTime )
- {
- SOLDIERTYPE *pSoldier;
- pSoldier = FindSoldierByProfileID( ArmsDealerInfo[ ubArmsDealer ].ubShopKeeperID, FALSE );
- if ( pSoldier == NULL )
- {
- return( FALSE );
- }
- if ( ExtractScheduleDoorLockAndUnlockInfo( pSoldier, puiOpeningTime, puiClosingTime ) == FALSE )
- {
- return( FALSE );
- }
- Assert( *puiOpeningTime < *puiClosingTime );
- return( TRUE );
- }
- UINT32 CalculateOvernightRepairDelay( UINT8 ubArmsDealer, UINT32 uiTimeWhenFreeToStartIt, UINT32 uiMinutesToFix )
- {
- UINT32 uiOpeningTime, uiClosingTime;
- UINT32 uiMinutesClosedOvernight;
- UINT32 uiDelayInDays = 0;
- UINT32 uiDoneToday;
- Assert( uiMinutesToFix > 0 );
- // convert world time into 24hr military time for the day he's gonna start on it
- uiTimeWhenFreeToStartIt = uiTimeWhenFreeToStartIt % NUM_MIN_IN_DAY;
- if ( GetArmsDealerShopHours( ubArmsDealer, &uiOpeningTime, &uiClosingTime ) == FALSE )
- {
- return( 0 );
- }
- // if it won't get done by the end of a day
- while ( ( uiTimeWhenFreeToStartIt + uiMinutesToFix ) > uiClosingTime )
- {
- // this is to handle existing saves with overnight repairs
- if ( uiTimeWhenFreeToStartIt < uiClosingTime )
- {
- // he gets this much done before closing
- uiDoneToday = uiClosingTime - uiTimeWhenFreeToStartIt;
- // subtract how much he got done
- uiMinutesToFix -= uiDoneToday;
- Assert( uiMinutesToFix > 0 );
- }
- // he starts back at it first thing in the morning
- uiTimeWhenFreeToStartIt = uiOpeningTime;
- uiDelayInDays++;
- }
- uiMinutesClosedOvernight = NUM_MIN_IN_DAY - ( uiClosingTime - uiOpeningTime );
- return ( uiDelayInDays * uiMinutesClosedOvernight );
- }
- UINT32 CalculateMinutesClosedBetween( UINT8 ubArmsDealer, UINT32 uiStartTime, UINT32 uiEndTime )
- {
- UINT32 uiOpeningTime, uiClosingTime;
- UINT32 uiMinutesClosedOvernight;
- UINT32 uiDaysDifference = 0;
- UINT32 uiMinutesClosed = 0;
- Assert( uiStartTime <= uiEndTime );
- if ( GetArmsDealerShopHours( ubArmsDealer, &uiOpeningTime, &uiClosingTime ) == FALSE )
- {
- return( 0 );
- }
- uiMinutesClosedOvernight = NUM_MIN_IN_DAY - ( uiClosingTime - uiOpeningTime );
- // NOTE: this assumes stored are only closed overnight, so all we have to do is compare the day portion
- uiDaysDifference = ( uiEndTime / NUM_MIN_IN_DAY ) - ( uiStartTime / NUM_MIN_IN_DAY );
- if ( uiDaysDifference >= 2 )
- {
- // close for 1 less than that many full nights...
- uiMinutesClosed = ( uiDaysDifference - 1 ) * uiMinutesClosedOvernight;
- }
- // add partial day's closing
- // convert start and end times into 24hr military time
- uiStartTime = uiStartTime % NUM_MIN_IN_DAY;
- uiEndTime = uiEndTime % NUM_MIN_IN_DAY;
- // treat end time of midnight as 24:00 hours to prevent indefinite recursion and make formulas work
- if ( uiEndTime == 0 )
- {
- uiEndTime = NUM_MIN_IN_DAY;
- }
- if ( uiStartTime == uiEndTime )
- {
- if ( uiDaysDifference == 0 )
- {
- return( 0 );
- }
- else
- {
- uiMinutesClosed += uiMinutesClosedOvernight;
- }
- }
- if ( uiStartTime < uiEndTime )
- {
- if ( uiStartTime < uiOpeningTime )
- {
- // add how many minutes in the time range BEFORE the store opened that day
- uiMinutesClosed += ( min( uiOpeningTime, uiEndTime ) - uiStartTime );
- }
- if ( uiEndTime > uiClosingTime )
- {
- // add how many minutes in the time range AFTER the store closed that day
- uiMinutesClosed += ( uiEndTime - max( uiClosingTime, uiStartTime ) );
- }
- }
- else
- {
- Assert( uiEndTime < uiStartTime );
- // recursive calls! Add two separate times: before midnight, and after midnight
- uiMinutesClosed += CalculateMinutesClosedBetween( ubArmsDealer, uiStartTime, NUM_MIN_IN_DAY );
- uiMinutesClosed += CalculateMinutesClosedBetween( ubArmsDealer, 0, uiEndTime );
- }
- return ( uiMinutesClosed );
- }
|