dw.c 87 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855
  1. /*++
  2. Copyright (c) 2015 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. dw.c
  5. Abstract:
  6. This module implements a utility to pass idle time.
  7. Author:
  8. Evan Green 23-Jul-2015
  9. Environment:
  10. POSIX
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/lib/types.h>
  16. #include <assert.h>
  17. #include <ctype.h>
  18. #include <errno.h>
  19. #include <fcntl.h>
  20. #include <getopt.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <time.h>
  24. #include <unistd.h>
  25. #include "swlib.h"
  26. //
  27. // --------------------------------------------------------------------- Macros
  28. //
  29. #define DwRedrawCash(_Context) \
  30. DwDrawStandardStat(DwString(DwsCash), 5, (_Context)->Cash, TRUE, FALSE)
  31. #define DwRedrawWeapons(_Context) \
  32. DwDrawStandardStat(DwString(DwsGuns), \
  33. 7, \
  34. (_Context)->WeaponCount, \
  35. FALSE, \
  36. FALSE)
  37. #define DwRedrawHealth(_Context) \
  38. DwDrawStandardStat(DwString(DwsHealth), \
  39. 9, \
  40. (_Context)->Health, \
  41. FALSE, \
  42. (_Context)->Health < 50)
  43. #define DwRedrawBank(_Context) \
  44. DwDrawStandardStat(DwString(DwsBank), 11, (_Context)->Bank, TRUE, FALSE)
  45. #define DwRedrawDebt(_Context) \
  46. DwDrawStandardStat(DwString(DwsDebt), 13, (_Context)->Debt, TRUE, TRUE)
  47. #define DW_HEALTH_COLOR(_Context) \
  48. (((_Context)->Health < 50) ? ConsoleColorDarkRed : ConsoleColorBlack)
  49. #define DwRedrawHighlightedHealth(_Context) \
  50. DwDrawStat(DwString(DwsHealth), \
  51. 9, \
  52. (_Context)->Health, \
  53. FALSE, \
  54. DW_HEALTH_COLOR(_Context), \
  55. ConsoleColorGray)
  56. #define DwDrawStandardStat(_Name, _Row, _Value, _Money, _Bad) \
  57. DwDrawStat((_Name), \
  58. (_Row), \
  59. (_Value), \
  60. (_Money), \
  61. (_Bad) ? ConsoleColorDarkRed : ConsoleColorGray, \
  62. (_Bad) ? ConsoleColorGray : ConsoleColorDarkBlue)
  63. #define DwClearLowerRegion() \
  64. SwClearRegion(ConsoleColorGray, ConsoleColorBlack, 0, 18, 80, 7)
  65. #define DwGoodName(_Index) DwString(DwsGoodsNames + (_Index))
  66. #define DwLocationName(_Index) DwString(DwsLocations + (_Index))
  67. #define DwWeaponName(_Index) DwString(DwsWeapons + (_Index))
  68. #define DwString(_Index) DwStrings[Context->Language][_Index]
  69. //
  70. // ---------------------------------------------------------------- Definitions
  71. //
  72. #define DW_VERSION_MAJOR 1
  73. #define DW_VERSION_MINOR 0
  74. #define DW_LANGUAGE_COUNT 2
  75. #define DW_INITIAL_CASH 2000
  76. #define DW_INITIAL_WEAPON_COUNT 0
  77. #define DW_INITIAL_WEAPON_DAMAGE 0
  78. #define DW_INITIAL_HEALTH 100
  79. #define DW_INITIAL_BANK 0
  80. #define DW_INITIAL_DEBT 5500
  81. #define DW_INITIAL_SPACE 100
  82. #define DW_INITIAL_LOCATION 0
  83. #define DW_INITIAL_DAY 1
  84. #define DW_GOOD_COUNT 12
  85. #define DW_LOCATION_COUNT 6
  86. #define DW_WEAPON_COUNT 4
  87. #define DW_GAME_TIME 31
  88. #define DW_SUBWAY_SAYINGS_COUNT 31
  89. #define DW_SONG_COUNT 18
  90. #define DW_PASSIVE_ACTIVITY_COUNT 5
  91. #define DW_FINANCIAL_DISTRICT 0
  92. #define DW_MORE_SPACE 10
  93. #define DW_MIN_SPACE_PRICE 200
  94. #define DW_MAX_SPACE_PRICE 300
  95. #define DW_FLASH_FAST_MICROSECONDS 150000
  96. #define DW_FLASH_SLOW_MICROSECONDS 200000
  97. //
  98. // Define the type of goods that brownies are made of.
  99. //
  100. #define DW_BROWNIE_GOOD1 2
  101. #define DW_BROWNIE_GOOD2 11
  102. //
  103. // Define the factors by which extreme prices fluctuate.
  104. //
  105. #define DW_SURGE_FACTOR 4
  106. #define DW_SALE_FACTOR 4
  107. //
  108. // Define the interest rates. Loans are brutal.
  109. //
  110. #define DW_LOAN_INTEREST_RATE 10
  111. #define DW_BANK_INTEREST_RATE 5
  112. //
  113. // Define high score information.
  114. //
  115. #define DW_HIGH_SCORE_MAGIC 0x65706F44
  116. #define DW_HIGH_SCORE_NAME_SIZE 22
  117. #define DW_HIGH_SCORE_VALID 0x00000001
  118. #define DW_HIGH_SCORE_ALIVE 0x00000002
  119. #define DW_HIGH_SCORE_YOU 0x80000000
  120. #define DW_HIGH_SCORE_COUNT 18
  121. //
  122. // ------------------------------------------------------ Data Type Definitions
  123. //
  124. /*++
  125. Structure Description:
  126. This structure stores the context for the dw application.
  127. Members:
  128. Backspace - Stores the backspace character.
  129. Cash - Stores the amount of cash the player has.
  130. WeaponCount - Stores the number of weapons the player has.
  131. WeaponDamage - Stores the sum of the damage the player's weapons can do.
  132. Health - Stores the amount of health the player has.
  133. Bank - Stores the amount the player has in the bank.
  134. Debt - Stores the amount of debt the player is carrying.
  135. Space - Stores the empty space the player has for more goods.
  136. Day - Stores the current (game) day of the month.
  137. Location - Stores the player's location.
  138. Inventory - Stores the player's inventory of goods, indexed by good.
  139. Market - Stores today's market prices.
  140. ExitRequested - Stores a boolean indicating that an exit was requested.
  141. Language - Stores the language index in use.
  142. --*/
  143. typedef struct _DW_CONTEXT {
  144. char Backspace;
  145. INT Cash;
  146. INT WeaponCount;
  147. INT WeaponDamage;
  148. INT Health;
  149. INT Bank;
  150. INT Debt;
  151. INT Space;
  152. INT Day;
  153. INT Location;
  154. INT Inventory[DW_GOOD_COUNT];
  155. INT Market[DW_GOOD_COUNT];
  156. BOOL ExitRequested;
  157. INT Language;
  158. } DW_CONTEXT, *PDW_CONTEXT;
  159. /*++
  160. Structure Description:
  161. This structure stores the data for a good.
  162. Members:
  163. MinPrice - Stores the minimum price of the good.
  164. MaxPrice - Stores the maximum price of the good.
  165. Sales - Stores a boolean indicating if the good goes on sale.
  166. Surges - Stores a boolean indicating if the good undergoes shortages.
  167. --*/
  168. typedef struct _DW_GOOD {
  169. INT MinPrice;
  170. INT MaxPrice;
  171. BOOL Sales;
  172. BOOL Surges;
  173. } DW_GOOD, *PDW_GOOD;
  174. /*++
  175. Structure Description:
  176. This structure stores the data for a location.
  177. Members:
  178. PolicePresence - Stores the likelihood that the player will have to deal
  179. with the popo when going here.
  180. MinGoods - Stores the minimum number of goods at this market.
  181. MaxGoods - Stores the maximum number of goods at this market.
  182. --*/
  183. typedef struct _DW_LOCATION {
  184. INT PolicePresence;
  185. INT MinGoods;
  186. INT MaxGoods;
  187. } DW_LOCATION, *PDW_LOCATION;
  188. /*++
  189. Structure Description:
  190. This structure stores the data for a weapon.
  191. Members:
  192. Price - Stores the price of the weapon.
  193. Space - Stores the amount of space the weapon takes up.
  194. Damage - Stores the amount of damage the weapon does.
  195. --*/
  196. typedef struct _DW_WEAPON {
  197. INT Price;
  198. INT Space;
  199. INT Damage;
  200. } DW_WEAPON, *PDW_WEAPON;
  201. /*++
  202. Structure Description:
  203. This structure stores a single high score entry.
  204. Members:
  205. Flags - Stores a bitfield of flags about this entry.
  206. Year - Stores the year of the high score.
  207. Month - Stores the month of the high score, 1-12.
  208. Day - Stores the day of the high score, 1-31.
  209. Amount - Stores the amount they had.
  210. Name - Stores the high scorer's name.
  211. --*/
  212. typedef struct _DW_HIGH_SCORE_ENTRY {
  213. ULONG Flags;
  214. USHORT Year;
  215. UCHAR Month;
  216. UCHAR Day;
  217. LONG Amount;
  218. CHAR Name[DW_HIGH_SCORE_NAME_SIZE];
  219. } DW_HIGH_SCORE_ENTRY, *PDW_HIGH_SCORE_ENTRY;
  220. /*++
  221. Structure Description:
  222. This structure stores the complete high score data.
  223. Members:
  224. Magic - Stores the magic value DW_HIGH_SCORE_MAGIC.
  225. Checksum - Stores the checksum of the table, assuming the checksum field
  226. itself is zero.
  227. Entries - Stores the array of high score entries.
  228. --*/
  229. typedef struct _DW_HIGH_SCORES {
  230. ULONG Magic;
  231. ULONG Checksum;
  232. DW_HIGH_SCORE_ENTRY Entries[DW_HIGH_SCORE_COUNT];
  233. } DW_HIGH_SCORES, *PDW_HIGH_SCORES;
  234. typedef enum _DW_STRING_VALUE {
  235. DwsIntroTitle,
  236. DwsIntroText,
  237. DwsHorizontalLine,
  238. DwsTwoColumnLine,
  239. DwsColumnTitles,
  240. DwsSubway,
  241. DwsMarketGreeting,
  242. DwsSurgeFormat1,
  243. DwsSurgeFormat2,
  244. DwsPressSpace,
  245. DwsBuyOrJet,
  246. DwsBuySellJet,
  247. DwsWhatToBuy,
  248. DwsWhatToSell,
  249. DwsHowManyToBuy,
  250. DwsHowManyToSell,
  251. DwsWhereTo,
  252. DwsSubwayLadyFormat,
  253. DwsSubwayQualifier,
  254. DwsHearSongFormat,
  255. DwsProductOfferFormat,
  256. DwsProductMoreSpace,
  257. DwsMugged,
  258. DwsReceiveGiftFormat,
  259. DwsSendGiftFormat,
  260. DwsLostGoodsFormat,
  261. DwsFoundGoodsFormat,
  262. DwsSharedGoodsFormat,
  263. DwsSirenSong,
  264. DwsSirenPrompt,
  265. DwsSirenResult,
  266. DwsPassiveActivityFormat,
  267. DwsFightThreatFormat,
  268. DwsRunOrFight,
  269. DwsRunOption,
  270. DwsFight,
  271. DwsRun,
  272. DwsPlayerFire,
  273. DwsPlayerMissed,
  274. DwsPlayerHit,
  275. DwsPlayerUnderFire,
  276. DwsFled,
  277. DwsFailedToFlee,
  278. DwsNotFleeing,
  279. DwsTheyMissed,
  280. DwsTheyHit,
  281. DwsKilled,
  282. DwsFightVictoryFormat,
  283. DwsDoctorOffer,
  284. DwsVisitLoanShark,
  285. DwsYes,
  286. DwsLoanRepaymentAmount,
  287. DwsVisitBank,
  288. DwsDepositOrWithdraw,
  289. DwsHowMuchMoney,
  290. DwsHighScoresTitle,
  291. DwsHighScoreDead,
  292. DwsHighScoreFormat,
  293. DwsPlayAgain,
  294. DwsMadeHighScores,
  295. DwsNamePrompt,
  296. DwsAnonymous,
  297. DwsYou,
  298. DwsGoodsNames,
  299. DwsGoodsSales = DwsGoodsNames + DW_GOOD_COUNT,
  300. DwsLocations = DwsGoodsSales + DW_GOOD_COUNT,
  301. DwsWeapons = DwsLocations + DW_LOCATION_COUNT,
  302. DwsSubwaySayings = DwsWeapons + DW_WEAPON_COUNT,
  303. DwsSongs = DwsSubwaySayings + DW_SUBWAY_SAYINGS_COUNT,
  304. DwsPassiveActivities = DwsSongs + DW_SONG_COUNT,
  305. DwsCash = DwsPassiveActivities + DW_PASSIVE_ACTIVITY_COUNT,
  306. DwsGuns,
  307. DwsHealth,
  308. DwsBank,
  309. DwsDebt,
  310. DwsAccess,
  311. DwsNoAccess,
  312. DwsStringCount
  313. } DW_STRING_VALUE, *PDW_STRING_VALUE;
  314. //
  315. // ----------------------------------------------- Internal Function Prototypes
  316. //
  317. INT
  318. DwDecodeStrings (
  319. PDW_CONTEXT Context
  320. );
  321. VOID
  322. DwDrawIntro (
  323. PDW_CONTEXT Context
  324. );
  325. VOID
  326. DwDrawGameBoard (
  327. PDW_CONTEXT Context
  328. );
  329. VOID
  330. DwResetGame (
  331. PDW_CONTEXT Context
  332. );
  333. VOID
  334. DwPlay (
  335. PDW_CONTEXT Context
  336. );
  337. VOID
  338. DwDoDailyEvents (
  339. PDW_CONTEXT Context
  340. );
  341. VOID
  342. DwReceiveOffer (
  343. PDW_CONTEXT Context
  344. );
  345. VOID
  346. DwPerformActOfGod (
  347. PDW_CONTEXT Context
  348. );
  349. VOID
  350. DwEncounterPolice (
  351. PDW_CONTEXT Context
  352. );
  353. VOID
  354. DwVisitFinancialDistrict (
  355. PDW_CONTEXT Context
  356. );
  357. VOID
  358. DwGenerateMarket (
  359. PDW_CONTEXT Context
  360. );
  361. VOID
  362. DwParticipateInMarket (
  363. PDW_CONTEXT Context
  364. );
  365. VOID
  366. DwDrawMarket (
  367. PDW_CONTEXT Context
  368. );
  369. VOID
  370. DwRedrawInventory (
  371. PDW_CONTEXT Context
  372. );
  373. VOID
  374. DwPresentNotification (
  375. PDW_CONTEXT Context,
  376. PSTR Notification
  377. );
  378. VOID
  379. DwDrawBottomPrompt (
  380. PSTR Prompt
  381. );
  382. VOID
  383. DwDrawStat (
  384. PSTR Name,
  385. INT Row,
  386. INT Value,
  387. BOOL Money,
  388. CONSOLE_COLOR Foreground,
  389. CONSOLE_COLOR Background
  390. );
  391. VOID
  392. DwDrawLocation (
  393. PSTR Location
  394. );
  395. VOID
  396. DwRedrawSpace (
  397. PDW_CONTEXT Context
  398. );
  399. VOID
  400. DwFlashText (
  401. PDW_CONTEXT Context,
  402. PSTR String,
  403. INT XPosition,
  404. INT YPosition,
  405. CONSOLE_COLOR Background,
  406. CONSOLE_COLOR Foreground,
  407. CONSOLE_COLOR FlashForeground,
  408. BOOL Fast
  409. );
  410. INT
  411. DwDisplayHighScores (
  412. PDW_CONTEXT Context
  413. );
  414. VOID
  415. DwLoadHighScores (
  416. PDW_CONTEXT Context,
  417. PDW_HIGH_SCORES Scores
  418. );
  419. INT
  420. DwHighScoresFileIo (
  421. PDW_HIGH_SCORES Scores,
  422. BOOL Load
  423. );
  424. int
  425. DwCompareHighScores (
  426. const void *LeftPointer,
  427. const void *RightPointer
  428. );
  429. VOID
  430. DwFormatMoney (
  431. PSTR String,
  432. UINTN StringSize,
  433. INT Value
  434. );
  435. INT
  436. DwReadCharacterSet (
  437. PDW_CONTEXT Context,
  438. PSTR Set
  439. );
  440. INT
  441. DwReadQuantity (
  442. PDW_CONTEXT Context
  443. );
  444. INT
  445. DwReadString (
  446. PDW_CONTEXT Context,
  447. PSTR String,
  448. INT StringSize
  449. );
  450. INT
  451. DwReadYesNoAnswer (
  452. PDW_CONTEXT Context,
  453. PSTR Exposition,
  454. PSTR Prompt
  455. );
  456. INT
  457. DwReadCharacter (
  458. PDW_CONTEXT Context
  459. );
  460. INT
  461. DwRandom (
  462. INT Minimum,
  463. INT Maximum
  464. );
  465. ULONG
  466. DwChecksum (
  467. PVOID Buffer,
  468. ULONG Size
  469. );
  470. //
  471. // -------------------------------------------------------------------- Globals
  472. //
  473. //
  474. // Store the menu of available goods and how they behave. Don't look!
  475. //
  476. DW_GOOD DwGoods[DW_GOOD_COUNT] = {
  477. {1000, 4000, TRUE, FALSE},
  478. {15000, 29000, FALSE, TRUE},
  479. {480, 1280, TRUE, FALSE},
  480. {5500, 13000, FALSE, TRUE},
  481. {11, 60, TRUE, FALSE},
  482. {1500, 4400, FALSE, FALSE},
  483. {540, 1250, FALSE, TRUE},
  484. {1000, 2500, FALSE, FALSE},
  485. {220, 700, FALSE, FALSE},
  486. {630, 1300, FALSE, FALSE},
  487. {90, 250, FALSE, TRUE},
  488. {315, 890, TRUE, FALSE}
  489. };
  490. DW_LOCATION DwLocations[DW_LOCATION_COUNT] = {
  491. {10, (DW_GOOD_COUNT / 2) + 2, DW_GOOD_COUNT},
  492. {5, (DW_GOOD_COUNT / 2) + 3, DW_GOOD_COUNT},
  493. {15, (DW_GOOD_COUNT / 2) + 1, DW_GOOD_COUNT},
  494. {90, (DW_GOOD_COUNT / 2), DW_GOOD_COUNT - 2},
  495. {20, (DW_GOOD_COUNT / 2) + 1, DW_GOOD_COUNT},
  496. {70, (DW_GOOD_COUNT / 2), DW_GOOD_COUNT - 1},
  497. };
  498. DW_WEAPON DwWeapons[DW_WEAPON_COUNT] = {
  499. {300, 4, 5},
  500. {350, 4, 9},
  501. {290, 4, 4},
  502. {310, 4, 7},
  503. };
  504. //
  505. // Define all the strings used in the game, localized. Do a very minimal effort
  506. // to hide from prying "strings".
  507. //
  508. PSTR DwStrings[DW_LANGUAGE_COUNT][DwsStringCount] = {
  509. {
  510. "E!P!Q!F!!!X!B!S!T",
  511. "!Cbtfe!po!Kpio!F/!Efmm(t!pme!Esvh!Xbst!hbnf-!Epqf!Xbst!jt!b!" \
  512. "tjnvmbujpo!pg!bo\n!jnbhjobsz!esvh!nbslfu/!!Epqf!xbst!jt!bo!" \
  513. "Bmm.Bnfsjdbo!hbnf!xijdi!gfbuvsft\n!cvzjoh-!tfmmjoh-!boe!uszjoh!" \
  514. "up!hfu!qbtu!uif!dpqt\"\n\n!Uif!gjstu!uijoh!zpv!offe!up!ep!jt!" \
  515. "qbz!pgg!zpvs!efcu!up!uif!Mpbo!Tibsl/!!Bgufs\n!uibu-!zpvs!hpbm!" \
  516. "jt!up!nblf!bt!nvdi!npofz!bt!qpttjcmf!)boe!tubz!bmjwf*\"!!Zpv\n!" \
  517. "ibwf!pof!npoui!pg!hbnf!ujnf!up!nblf!zpvs!gpsuvof/\n\n!Epqf!Xbst!" \
  518. "ibt!cffo!cspvhiu!up!zpv!dpvsuftz!pg!uif!Ibqqz!Ibdlfs!Gpvoebujpo/",
  519. ",>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" \
  520. ">>>>>>>>>,",
  521. "}!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" \
  522. "!!!!!!!!!}",
  523. "}!!!!!!!!!!!!Tubut!!!!!!!!!!!!}!Dfousbm!Qbsl!!}!!!!!!!!!!Usfodidpbu!" \
  524. "!!!!!!!!!}",
  525. "!T!V!C!X!B!Z",
  526. "Ifz!evef-!uif!qsjdft!pg!esvht!ifsf!bsf;",
  527. "Dpqt!nbef!b!cjh!&t!cvtu\"!!Qsjdft!bsf!pvusbhfpvt\"",
  528. "Beejdut!bsf!cvzjoh!&t!bu!pvusbhfpvt!qsjdft\"",
  529. "Qsftt!TQBDF!up!dpoujovf",
  530. "Xjmm!zpv!C?vz-!ps!K?fu@!",
  531. "Xjmm!zpv!C?vz-!T?fmm-!ps!K?fu@!",
  532. "Xibu!ep!zpv!xjti!up!cvz@!",
  533. "Xibu!ep!zpv!xjui!up!tfmm@!",
  534. "Zpv!dbo!bggpse!&e/!!Ipx!nboz!ep!zpv!cvz@!",
  535. "Zpv!ibwf!&e/!!Ipx!nboz!ep!zpv!tfmm@!",
  536. "Xifsf!up-!evef@",
  537. "Uif!mbez!ofyu!up!zpv!po!uif!tvcxbz!tbje-\n!!!!!#&t#///\n!&t",
  538. ")bu!mfbtu-!zpv!.uijol.!uibu(t!xibu!tif!tbje*/",
  539. "Zpv!ifbs!tpnfpof!qmbzjoh!&t",
  540. "Xpvme!zpv!mjlf!up!cvz!b!&t!gps!%&e@!",
  541. "cjhhfs!usfodidpbu",
  542. "Zpv!xfsf!nvhhfe!jo!uif!tvcxbz\"",
  543. "Zpv!nffu!b!gsjfoe\"!!If!mbzt!tpnf!&t!po!zpv/",
  544. "Zpv!nffu!b!gsjfoe\"!!Zpv!hjwf!ifs!tpnf!&t/",
  545. "Qpmjdf!epht!dibtfe!zpv!gps!&e!cmpdlt\"\n!Zpv!espqqfe!tpnf!esvht\"!!" \
  546. "Uibu(t!b!esbh-!nbo/",
  547. "Zpv!gjoe!&e!vojut!pg!&t!po!b!efbe!evef!jo!uif!tvcxbz/",
  548. "Zpvs!nbnb!nbef!cspxojft!xjui!tpnf!pg!zpvs!&t\"!!Uifz!xfsf!hsfbu\"",
  549. "Uifsf!jt!tpnf!xffe!uibu!tnfmmt!mjlf!qbsbrvbu!ifsf\"!!Ju!mpplt!hppe\"",
  550. "Xjmm!zpv!tnplf!ju@!",
  551. "Zpv!ibmmvdjobufe!gps!uisff!ebzt!po!uif!xjmeftu!usjq!zpv!fwfs!" \
  552. "jnbhjofe\"\n!Uifo!zpv!ejfe!cfdbvtf!zpvs!csbjo!ejtjoufhsbufe\"",
  553. "Zpv!tupqqfe!up!&t/",
  554. "Pggjdfs!Ibsebtt!boe!&e!pg!ijt!efqvujft!bsf!dibtjoh!zpv\"",
  555. "Xjmm!zpv!S?vo!ps!G?jhiu@!",
  556. "Xjmm!zpv!svo@!",
  557. "Gjhiu",
  558. "Svo",
  559. "Zpv(sf!gjsjoh!po!uifn\"!!",
  560. "Zpv!njttfe\"",
  561. "Zpv!ljmmfe!pof\"",
  562. "Uifz!bsf!gjsjoh!po!zpv-!nbo\"!!",
  563. "Zpv!mptu!uifn!jo!uif!bmmfzt/",
  564. "Zpv!dbo(u!mptf!uifn\"",
  565. "Zpv!tuboe!uifsf!mjlf!bo!jejpu/",
  566. "Uifz!njttfe\"",
  567. "Zpv(wf!cffo!iju\"",
  568. "Uifz!xbtufe!zpv!nbo\"!!Xibu!b!esbh\"",
  569. "Zpv!ljmmfe!bmm!pg!uifn\"\n!Zpv!gjoe!%&e!po!Pggjdfs!Ibsebtt(!" \
  570. "dbsdbtt\"\n!",
  571. "Xjmm!zpv!qbz!%&e!up!ibwf!b!epdups!tfx!zpv!vq@!",
  572. "Xpvme!zpv!mjlf!up!wjtju!uif!Mpbo!Tibsl@!",
  573. "Zft",
  574. "Ipx!nvdi!ep!zpv!hjwf!ijn@!",
  575. "Xpvme!zpv!mjlf!up!wjtju!uif!Cbol@!",
  576. "Ep!zpv!xbou!up!E?fqptju!ps!X?juiesbx@!",
  577. "Ipx!nvdi!npofz@!",
  578. "I!J!H!I!!!T!D!P!S!F!T",
  579. ")S/J/Q/*",
  580. "&23t!!!!!!!!!!&13e.&13e.&15e!!!!!!!!!!&.31t&t",
  581. "Qmbz!bhbjo@",
  582. "Dpohsbuvmbujpot\"!!Zpv!nbef!uif!Ijhi!Tdpsft!mjtu\"\n!",
  583. "Qmfbtf!foufs!zpvs!obnf;!",
  584. "Nztufsz!Efbmfs",
  585. "+++!ZPV!+++",
  586. "Bdje",
  587. "Dpdbjof",
  588. "Ibtijti",
  589. "Ifspjo",
  590. "Mveft",
  591. "NEB",
  592. "Pqjvn",
  593. "QDQ",
  594. "Qfzpuf",
  595. "Tisppnt",
  596. "Tqffe",
  597. "Xffe",
  598. "Uif!nbslfu!ibt!cffo!gmppefe!xjui!difbq!ipnf.nbef!bdje\"",
  599. NULL,
  600. "Uif!Nbssblfti!Fyqsftt!ibt!bssjwfe\"",
  601. NULL,
  602. "Sjwbm!esvh!efbmfst!sbjefe!b!qibsnbdz!boe!bsf!tfmmjoh!difbq!mveft\"",
  603. NULL,
  604. NULL,
  605. NULL,
  606. NULL,
  607. NULL,
  608. NULL,
  609. "Dpmvncjbo!gsfjhiufs!evtufe!uif!Dpbtu!Hvbse\"\n!Xffe!qsjdft!ibwf!" \
  610. "cpuupnfe!pvu\"",
  611. "Cspoy",
  612. "Hifuup",
  613. "Dfousbm!Qbsl",
  614. "Nboibuubo",
  615. "Dpofz!Jtmboe",
  616. "Cspplmzo",
  617. "Cbsfuub",
  618. "/49!Tqfdjbm",
  619. "Svhfs",
  620. "Tbuvsebz!Ojhiu!Tqfdjbm",
  621. "Xpvmeo(u!ju!cf!gvooz!jg!fwfszpof!tveefomz!rvbdlfe!bu!podf@",
  622. "Uif!Qpqf!xbt!podf!Kfxjti-!zpv!lopx",
  623. "J(mm!cf!zpv!ibwf!tpnf!sfbmmz!joufsftujoh!esfbnt",
  624. "Tp!J!uijol!J(n!hpjoh!up!Bntufsebn!uijt!zfbs",
  625. "Tpo-!zpv!offe!b!zfmmpx!ibjsdvu",
  626. "J!uijol!ju(t!xpoefsgvm!xibu!uifz(sf!epjoh!xjui!jodfotf!uiftf!ebzt",
  627. "J!xbto(u!bmxbzt!b!xpnbo-!zpv!lopx",
  628. "Epft!zpvs!npuifs!lopx!zpv(sf!b!epqf!efbmfs@",
  629. "Bsf!zpv!ijhi!po!tpnfuijoh@",
  630. "Pi-!zpv!nvtu!cf!gspn!Dbmjgpsojb",
  631. "J!vtfe!up!cf!b!ijqqjf-!nztfmg",
  632. "Uifsf(t!opuijoh!mjlf!ibwjoh!mput!pg!npofz",
  633. "Zpv!mppl!mjlf!bo!bbsewbsl\"",
  634. "J!epo(u!cfmjfwf!jo!Spobme!Sfbhbo",
  635. "Dpvsbhf\"!!Cvti!jt!b!oppemf\"",
  636. "Ibwfo(u!J!tffo!zpv!po!UW@",
  637. "J!uijol!ifnpssipje!dpnnfsdjbmt!bsf!sfbmmz!ofbu\"",
  638. "Xf(sf!xjoojoh!uif!xbs!gps!esvht\"",
  639. "B!ebz!xjuipvu!epqf!jt!mjlf!ojhiu",
  640. "Xf!pomz!vtf!31&!pg!pvs!csbjot-!tp!xiz!opu!cvso!pvu!uif!puifs!91&",
  641. "J(n!tpmjdjujoh!dpousjcvujpot!gps![pncjft!gps!Disjtu",
  642. "J(e!mjlf!up!tfmm!zpv!bo!fejcmf!qppemf",
  643. "Xjoofst!epo(u!ep!esvht///!vomftt!uifz!ep",
  644. "Ljmm!b!dpq!gps!Disjtu\"",
  645. "J!bn!uif!xbmsvt\"",
  646. "Kftvt!mpwft!zpv!npsf!uibo!zpv!xjmm!lopx",
  647. "J!gffm!bo!vobddpvoubcmf!vshf!up!ezf!nz!ibjs!cmvf",
  648. "Xbto(u!Kbof!Gpoeb!xpoefsgvm!jo!Cbscbsfmmb",
  649. "Kvtu!tbz!Op//!xfmm-!nbzcf///!pl-!xibu!uif!ifmm\"",
  650. "Xpvme!zpv!mjlf!b!kfmmz!cbcz@",
  651. "Esvht!dbo!cf!zpvs!gsjfoe\"",
  652. "#Bsf!Zpv!Fyqfsjfodfe#!cz!Kjnj!Ifoesjy",
  653. "#Diffcb!Diffcb#!cz!Upof!Mpd",
  654. "#Dpnjo(!jo!up!Mpt!Bohfmft#!cz!Bsmp!Hvuisjf",
  655. "#Dpnnfsdjbm#!cz!Tqbolz!boe!Pvs!Hboh",
  656. "#Mbuf!jo!uif!Fwfojoh#!cz!Qbvm!Tjnpo",
  657. "#Mjhiu!Vq#!cz!Tuzy",
  658. "#Nfyjdp#!cz!Kfggfstpo!Bjsqmbof",
  659. "#Pof!Uplf!Pwfs!uif!Mjof#!cz!Csfxfs!'!Tijqmfz",
  660. "#Uif!Tnplfpvu#!cz!Tifm!Tjmwfstufjo",
  661. "#Xijuf!Sbccju#!cz!Kfggfstpo!Bjsqmbof",
  662. "#Judizdpp!Qbsl#!cz!Tnbmm!Gbdft",
  663. "#Xijuf!Qvolt!po!Epqf#!cz!Uif!Uvcft",
  664. "#Mfhfoe!pg!b!Njoe#!cz!Uif!Nppez!Cmvft",
  665. "#Fjhiu!Njmft!Ijhi#!cz!Uif!Czset",
  666. "#Bdbqvmdp!Hpme#!cz!Sjefst!pg!uif!Qvsqmf!Tbhf",
  667. "#Ljdlt#!cz!Qbvm!Sfwfsf!'!uif!Sbjefst",
  668. "uif!Ojypo!ubqft",
  669. "#Mfhbmj{f!Ju#!cz!Npkp!Ojypo!'!Tlje!Spqfs",
  670. "ibwf!b!cffs",
  671. "tnplf!b!kpjou",
  672. "tnplf!b!djhbs",
  673. "tnplf!b!Ekbsvn",
  674. "tnplf!b!djhbsfuuf",
  675. "Dbti",
  676. "Hvot",
  677. "Ifbmui",
  678. "Cbol",
  679. "Efcu",
  680. "EX`QMBZ`PME`TDIPPM",
  681. "ti;!ex;!Dpnnboe!opu!gpvoe/\n",
  682. },
  683. {
  684. "D!B!O!E!Z!!!X!B!S!T",
  685. "!Cbtfe!po!Kpio!F/!Efmm(t!pme!usbejoh!hbnf-!Dboez!Xbst!jt!b!" \
  686. "tjnvmbujpo!pg!bo\n!jnbhjobsz!dboez!nbslfu/!!Dboez!Xbst!jt!bo!" \
  687. "Bmm.Bnfsjdbo!hbnf!xijdi!gfbuvsft\n!cvzjoh-!tfmmjoh-!boe!uszjoh!" \
  688. "up!hfu!qbtu!uif!wfhhjf!qpmjdf\"\n\n!Uif!gjstu!uijoh!zpv!offe!" \
  689. "up!ep!jt!qbz!pgg!zpvs!efcu!up!uif!Mpbo!Tibsl/!!Bgufs\n!uibu-!" \
  690. "zpv!hpbm!jt!up!nblf!bt!nvdi!npofz!bt!qpttjcmf!)boe!tubz!" \
  691. "bmjwf*\"!!Zpv\n!ibwf!pof!npoui!pg!hbnf!ujnf!up!nblf!zpvs!" \
  692. "gpsuvof/\n\n",
  693. ",>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" \
  694. ">>>>>>>>>>>>,",
  695. "}!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}!!!!!!!!!!!!!!!!!!!!!!!!!!" \
  696. "!!!!!!!!!!!!}",
  697. "}!!!!!!!!!!!!Tubut!!!!!!!!!!!!}!Dfousbm!Qbsl!!}!!!!!!!!!!Usfodidpbu" \
  698. "!!!!!!!!!!}",
  699. "!!C!!!V!!!T!",
  700. "Ifz!evef-!uif!qsjdft!pg!dboez!ifsf!bsf;",
  701. "Uif!GEB!nbef!b!cjh!&t!cvtu\"!!Qsjdft!bsf!pvusbhfpvt\"",
  702. "Beejdut!bsf!cvzjoh!&t!bu!pvusbhfpvt!qsjdft\"",
  703. "Qsftt!TQBDF!up!dpoujovf",
  704. "Xjmm!zpv!C?vz-!ps!K?fu@!",
  705. "Xjmm!zpv!C?vz-!T?fmm-!ps!K?fu@!",
  706. "Xibu!ep!zpv!xjti!up!cvz@!",
  707. "Xibu!ep!zpv!xjui!up!tfmm@!",
  708. "Zpv!dbo!bggpse!&e/!!Ipx!nboz!ep!zpv!cvz@!",
  709. "Zpv!ibwf!&e/!!Ipx!nboz!ep!zpv!tfmm@!",
  710. "Xifsf!up-!evef@",
  711. "Uif!mbez!ofyu!up!zpv!po!uif!cvt!tbje-\n!!!!!#&t#///\n!&t",
  712. ")bu!mfbtu-!zpv!.uijol.!uibu(t!xibu!tif!tbje*/",
  713. "Zpv!ifbs!tpnfpof!qmbzjoh!&t",
  714. "Xpvme!zpv!mjlf!up!cvz!b!&t!gps!%&e@!",
  715. "cjhhfs!usfodidpbu",
  716. "Zpv!xfsf!nvhhfe!jo!uif!cvt!tubujpo\"",
  717. "Zpv!nffu!b!gsjfoe\"!!If!mbzt!tpnf!&t!po!zpv/",
  718. "Zpv!nffu!b!gsjfoe\"!!Zpv!hjwf!ifs!tpnf!&t/",
  719. "Dsb{fe!dijmesfo!dibtfe!zpv!gps!&e!cmpdlt\"\n!Zpv!espqqfe!tpnf!" \
  720. "dboez\"!!Uibu(t!b!esbh-!nbo/",
  721. "Zpv!gjoe!&e!vojut!pg!&t!bu!uif!cpuupn!pg!b!wfoejoh!nbdijof/",
  722. "Zpvs!nbnb!nbef!cspxojft!xjui!tpnf!pg!zpvs!&t\"!!Uifz!xfsf!hsfbu\"",
  723. "Uifsf!jt!tpnf!tpeb!ifsf!uibu!mpplt!mjlf!Ofx!Dplf\"!!Ju!mpplt!mfhju\"",
  724. "Xjmm!zpv!esjol!ju@!",
  725. "Zpv!ibmmvdjobufe!gps!uisff!ebzt!po!uif!xjmeftu!usjq!zpv!fwfs!" \
  726. "jnbhjofe\"\n!Uifo!zpv!ejfe!cfdbvtf!zpvs!csbjo!ejtjoufhsbufe\"",
  727. "Zpv!tupqqfe!up!&t/",
  728. "Dbqubjo!Wfhfubcmft!boe!&e!pg!ijt!dspojft!bsf!dibtjoh!zpv\"",
  729. "Xjmm!zpv!S?vo!ps!G?jhiu@!",
  730. "Xjmm!zpv!svo@!",
  731. "Gjhiu",
  732. "Svo",
  733. "Zpv(sf!gjsjoh!po!uifn\"!!",
  734. "Zpv!njttfe\"",
  735. "Zpv!hpu!pof\"",
  736. "Uifz!bsf!gjsjoh!po!zpv-!nbo\"!!",
  737. "Zpv!mptu!uifn!jo!uif!tvqfsnbslfu/",
  738. "Zpv!dbo(u!mptf!uifn\"",
  739. "Zpv!tuboe!uifsf!mjlf!bo!jejpu/",
  740. "Uifz!njttfe\"",
  741. "Zpv(wf!cffo!iju\"",
  742. "Uifz!dpowfsufe!zpv!up!b!wfhbo\"!!Xibu!b!esbh\"",
  743. "Zpv!hpu!bmm!pg!uifn\"\n!Zpv!gjoe!%&e!po!Dbqubjo!Wfhfubcmft(!" \
  744. "usvol\"\n!",
  745. "Xjmm!zpv!qbz!%&e!up!ibwf!b!epdups!gjy!zpv!vq@!",
  746. "Xpvme!zpv!mjlf!up!wjtju!uif!Mpbo!Tibsl@!",
  747. "Zft",
  748. "Ipx!nvdi!ep!zpv!hjwf!ijn@!",
  749. "Xpvme!zpv!mjlf!up!wjtju!uif!Cbol@!",
  750. "Ep!zpv!xbou!up!E?fqptju!ps!X?juiesbx@!",
  751. "Ipx!nvdi!npofz@!",
  752. "I!J!H!I!!!T!D!P!S!F!T",
  753. ")wfhbo*",
  754. "&23t!!!!!!!!!!&13e.&13e.&15e!!!!!!!!!!&.31t&t",
  755. "Qmbz!bhbjo@",
  756. "Dpohsbuvmbujpot\"!!Zpv!nbef!uif!Ijhi!Tdpsft!mjtu\"\n!",
  757. "Qmfbtf!foufs!zpvs!obnf;!",
  758. "Nztufsz!Efbmfs",
  759. "+++!ZPV!+++",
  760. "BjsIfbet",
  761. "Dbecvsz",
  762. "Ljttft",
  763. "Tljuumft",
  764. "Ujd!Ubdt",
  765. "Nbmu!Cbmmt",
  766. "Qjyjf!Tujy",
  767. "Qpq!Spdlt",
  768. "Qf{",
  769. "Cmpx!Qpqt",
  770. "Tubscvstu",
  771. "N'Nt",
  772. "Uif!nbslfu!ibt!cffo!gmppefe!xjui!difbq!ipnf.nbef!BjsIfbet\"",
  773. NULL,
  774. "Ju(t!Wbmfoujof(t!Ebz\"!Ljttft!bsf!po!tbmf\"",
  775. NULL,
  776. "Sjwbm!hspdfsz!tupsft!bsf!tfmmjoh!difbq!pgg.csboe!Ujd.Ubdt\"",
  777. NULL,
  778. NULL,
  779. NULL,
  780. NULL,
  781. NULL,
  782. NULL,
  783. "B!Ifstifz(t!usvdl!dsbtife!po!uif!ijhixbz\"\nN'Nt!bsf!fwfszxifsf-!" \
  784. "qsjdft!ibwf!cpuupnfe!pvu\"",
  785. "Njttjpo",
  786. "Dbtusp",
  787. "Qsftjejp",
  788. "Tvotfu",
  789. "Svttjbo!Ijmm",
  790. "Qpusfsp",
  791. "Tvqfs!Tpblfs",
  792. "Qfmmfu!Hvo",
  793. "Sfe!Szefs",
  794. "Dbq!Hvo",
  795. "Xpvmeo(u!ju!cf!gvooz!jg!fwfszpof!tveefomz!rvbdlfe!bu!podf@",
  796. "Uif!Qpqf!xbt!podf!Kfxjti-!zpv!lopx",
  797. "J(mm!cf!zpv!ibwf!tpnf!sfbmmz!joufsftujoh!esfbnt",
  798. "Tp!J!uijol!J(n!hpjoh!up!Qfootzmwbojb!uijt!zfbs",
  799. "Tpo-!zpv!offe!b!zfmmpx!ibjsdvu",
  800. "J!uijol!ju(t!xpoefsgvm!xibu!uifz(sf!epjoh!xjui!nbqmf!tzsvq!uiftf!ebzt",
  801. "J!xbto(u!bmxbzt!b!xpnbo-!zpv!lopx",
  802. "Epft!zpvs!npuifs!lopx!zpv!fbu!tp!nvdi!dboez@",
  803. "Zpv(sf!tvsf!cpvodz-!bsfo(u!zpv@",
  804. "Pi-!zpv!nvtu!cf!gspn!Dbmjgpsojb",
  805. "J!vtfe!up!cf!b!ijqqjf-!nztfmg",
  806. "Uifsf(t!opuijoh!mjlf!ibwjoh!mput!pg!npofz",
  807. "Zpv!mppl!mjlf!bo!bbsewbsl\"",
  808. "J!epo(u!cfmjfwf!jo!dmbttjdbm!qiztjdt",
  809. "Dpvsbhf\"!!Tjsj!jt!b!oppemf\"",
  810. "Ibwfo(u!J!tffo!zpv!po!UW@",
  811. "J!uijol!Hfpshf!Gpsfnbo!hsjmmt!bsf!sfbmmz!ofbu\"",
  812. "Xf(sf!xjoojoh!uif!xbs!gps!dpuupo!dboez\"",
  813. "B!ebz!xjuipvu!dboez!jt!mjlf!ojhiu",
  814. "J!dbo(u!cfmjfwf!J(n!opu!cvuufs\"",
  815. "J(n!tpmjdjujoh!dpousjcvujpot!gps![pncjft!gps!Cveeib",
  816. "J(e!mjlf!up!tfmm!zpv!fejcmf!upjmfu!qbqfs",
  817. "Ofwfs!Yfspy!cvccmf!hvn",
  818. "Nz!Lju.Lbu!cbst!dpnf!jo!gjwft\"",
  819. "J!bn!uif!xbmsvt\"",
  820. "Kftvt!mpwft!zpv!npsf!uibo!zpv!xjmm!lopx",
  821. "J!gffm!bo!vobddpvoubcmf!vshf!up!ezf!nz!ibjs!cmvf",
  822. "Xbto(u!Kbof!Gpoeb!xpoefsgvm!jo!Cbscbsfmmb",
  823. "Opuijoh!siznft!xjui!psbohf!///!fydfqu!cpsbohf\"",
  824. "Xpvme!zpv!mjlf!b!kfmmz!cbcz@",
  825. "Dboez!dbo!cf!zpvs!gsjfoe\"",
  826. "#J!Xbou!Dboez#!cz!Cpx!Xpx!Xpx",
  827. "#Npuifs!Qpqdpso#!cz!Kbnft!Cspxo",
  828. "#J!Dbo(u!Ifmq!Nztfmg#!cz!Uif!Gpvs!Upqt",
  829. "#Tvhbs-!Tvhbs#!cz!Uif!Bsdijft",
  830. "#Dvqt!boe!Dblft#!cz!TqjobmUbq",
  831. "#D!jt!gps!Dppljf#!cz!uif!Dppljf!Npotufs",
  832. "#Mft!Tvdfuuft#!cz!Gsbodf!Hbmmf",
  833. "#Dboeznbo#!cz!Brvb-!Brvb",
  834. "#Tbwpz!Usvggmf#!cz!Uif!Cfbumft",
  835. "#Dipdpmbuf!Kftvt#!cz!Upn!Xbjut",
  836. "#Tusbxcfssz!Gjfmet!Gpsfwfs#!cz!Uif!Cfbumft",
  837. "#Tvhbs!Nbhopmjb#!cz!Uif!Hsbufgvm!Efbe",
  838. "#Cspxo!Tvhbs#!cz!Uif!Spmmjoh!Tupoft",
  839. "#Qfbdift#!cz!Uif!Qsftjefout!pg!uif!Vojufe!Tubuft",
  840. "#Xjme!Ipofz!Qjf#!cz!Uif!Cfbumft",
  841. "#Ebodf!pg!uif!Tvhbs!Qmvn!Gbjsz#!cz!Udibjlpwtlz",
  842. "#B!Tqppogvm!pg!Tvhbs#!cz!Kvmjf!Boesfxt",
  843. "#Qpvs!Tpnf!Tvhbs!Po!Nf#!cz!Efg!Mfqqbse",
  844. "ibwf!b!cvshfs",
  845. "ibwf!tpnf!dpggff",
  846. "hsbc!b!rvjdl!gjy!zpvstfmg",
  847. "hsbc!tpnf!mvodi",
  848. "ibwf!b!dboez!djhbsfuuf",
  849. "Npofz",
  850. "Xfbqpot",
  851. "Ifbmui",
  852. "Cbol",
  853. "Efcu",
  854. "EX`QMBZ",
  855. "ti;!ex;!Dpnnboe!opu!gpvoe/\n",
  856. },
  857. };
  858. BOOL DwStringsDecoded;
  859. INT DwRandomSource;
  860. //
  861. // ------------------------------------------------------------------ Functions
  862. //
  863. INT
  864. DwMain (
  865. INT ArgumentCount,
  866. CHAR **Arguments
  867. )
  868. /*++
  869. Routine Description:
  870. This routine is the main entry point for the dw utility.
  871. Arguments:
  872. ArgumentCount - Supplies the number of command line arguments the program
  873. was invoked with.
  874. Arguments - Supplies a tokenized array of command line arguments.
  875. Return Value:
  876. Returns an integer exit code. 0 for success, nonzero otherwise.
  877. --*/
  878. {
  879. DW_CONTEXT Context;
  880. INT PlayAgain;
  881. INT Result;
  882. //
  883. // Seed the bad randomizer, and try to open a decent random source.
  884. //
  885. DwRandomSource = open("/dev/urandom", O_RDONLY | O_NONBLOCK);
  886. if (DwRandomSource < 0) {
  887. DwRandomSource = open("/dev/random", O_RDONLY | O_NONBLOCK);
  888. }
  889. srand(time(NULL));
  890. memset(&Context, 0, sizeof(Context));
  891. Result = DwDecodeStrings(&Context);
  892. if (Result != 0) {
  893. goto MainEnd;
  894. }
  895. SwSetRawInputMode(NULL, NULL);
  896. DwDrawIntro(&Context);
  897. if (DwReadCharacterSet(&Context, " ") == -1) {
  898. goto MainEnd;
  899. }
  900. //
  901. // Shall we play a game?
  902. //
  903. do {
  904. DwResetGame(&Context);
  905. DwPlay(&Context);
  906. PlayAgain = DwDisplayHighScores(&Context);
  907. } while (PlayAgain == 1);
  908. SwClearRegion(ConsoleColorDefault, ConsoleColorDefault, 0, 0, 80, 25);
  909. SwMoveCursor(stdout, 0, 0);
  910. Result = 0;
  911. MainEnd:
  912. if (DwRandomSource >= 0) {
  913. close(DwRandomSource);
  914. }
  915. SwRestoreInputMode();
  916. return Result;
  917. }
  918. //
  919. // --------------------------------------------------------- Internal Functions
  920. //
  921. INT
  922. DwDecodeStrings (
  923. PDW_CONTEXT Context
  924. )
  925. /*++
  926. Routine Description:
  927. This routine decodes all the strings used the app.
  928. Arguments:
  929. Context - Supplies a pointer to the application context.
  930. Return Value:
  931. 0 on success.
  932. ENOMEM on allocation failure.
  933. 127 if the proper conditions were not met.
  934. --*/
  935. {
  936. PSTR Buffer;
  937. ULONG Language;
  938. PSTR NewString;
  939. BOOL Print;
  940. size_t Size;
  941. PSTR Source;
  942. DW_STRING_VALUE StringIndex;
  943. if (DwStringsDecoded != FALSE) {
  944. return 0;
  945. }
  946. Print = FALSE;
  947. Size = 0;
  948. for (Language = 0; Language < DW_LANGUAGE_COUNT; Language += 1) {
  949. for (StringIndex = 0; StringIndex < DwsStringCount; StringIndex += 1) {
  950. Source = DwStrings[Language][StringIndex];
  951. if (Source != NULL) {
  952. Size += strlen(Source) + 1;
  953. }
  954. }
  955. }
  956. Buffer = malloc(Size);
  957. if (Buffer == NULL) {
  958. return ENOMEM;
  959. }
  960. for (Language = 0; Language < DW_LANGUAGE_COUNT; Language += 1) {
  961. if (Print != FALSE) {
  962. printf(" {\n");
  963. }
  964. for (StringIndex = 0; StringIndex < DwsStringCount; StringIndex += 1) {
  965. Source = DwStrings[Language][StringIndex];
  966. if (Source != NULL) {
  967. NewString = Buffer;
  968. if (Print != FALSE) {
  969. printf(" \"");
  970. }
  971. while (*Source != '\0') {
  972. if (*Source == '\n') {
  973. *Buffer = '\n';
  974. } else {
  975. *Buffer = *Source - 1;
  976. }
  977. if (Print != FALSE) {
  978. if (*Buffer == '\n') {
  979. printf("\\n");
  980. } else if (*Buffer == '"') {
  981. printf("\\\"");
  982. } else {
  983. printf("%c", *Buffer);
  984. }
  985. }
  986. Source += 1;
  987. Buffer += 1;
  988. }
  989. if (Print != FALSE) {
  990. printf("\",\n");
  991. }
  992. *Buffer = '\0';
  993. Buffer += 1;
  994. DwStrings[Language][StringIndex] = NewString;
  995. } else {
  996. if (Print != FALSE) {
  997. printf(" NULL,\n");
  998. }
  999. }
  1000. }
  1001. if (Print != FALSE) {
  1002. printf(" },\n");
  1003. }
  1004. }
  1005. DwStringsDecoded = TRUE;
  1006. for (Language = 0; Language < DW_LANGUAGE_COUNT; Language += 1) {
  1007. if (getenv(DwStrings[Language][DwsAccess]) != NULL) {
  1008. Context->Language = Language;
  1009. break;
  1010. }
  1011. }
  1012. if (Language == DW_LANGUAGE_COUNT) {
  1013. fprintf(stderr, "%s", DwString(DwsNoAccess));
  1014. return 127;
  1015. }
  1016. return 0;
  1017. }
  1018. VOID
  1019. DwDrawIntro (
  1020. PDW_CONTEXT Context
  1021. )
  1022. /*++
  1023. Routine Description:
  1024. This routine prepares the console and draws the introductory screen.
  1025. Arguments:
  1026. Context - Supplies a pointer to the application context.
  1027. Return Value:
  1028. None.
  1029. --*/
  1030. {
  1031. SwClearRegion(ConsoleColorGray, ConsoleColorDefault, 0, 0, 80, 25);
  1032. SwMoveCursor(stdout, 30, 0);
  1033. SwPrintInColor(ConsoleColorGray,
  1034. ConsoleColorDarkBlue,
  1035. DwString(DwsIntroTitle));
  1036. SwMoveCursor(stdout, 0, 5);
  1037. SwPrintInColor(ConsoleColorGray, ConsoleColorBlack, DwString(DwsIntroText));
  1038. DwDrawBottomPrompt(DwString(DwsPressSpace));
  1039. return;
  1040. }
  1041. VOID
  1042. DwResetGame (
  1043. PDW_CONTEXT Context
  1044. )
  1045. /*++
  1046. Routine Description:
  1047. This routine resets the game context.
  1048. Arguments:
  1049. Context - Supplies a pointer to the application context.
  1050. Return Value:
  1051. None.
  1052. --*/
  1053. {
  1054. INT Index;
  1055. Context->Backspace = 0x7F;
  1056. Context->Cash = DW_INITIAL_CASH;
  1057. Context->WeaponCount = DW_INITIAL_WEAPON_COUNT;
  1058. Context->WeaponDamage = DW_INITIAL_WEAPON_DAMAGE;
  1059. Context->Health = DW_INITIAL_HEALTH;
  1060. Context->Bank = DW_INITIAL_BANK;
  1061. Context->Debt = DW_INITIAL_DEBT;
  1062. Context->Space = DW_INITIAL_SPACE;
  1063. Context->Day = DW_INITIAL_DAY;
  1064. Context->Location = DW_INITIAL_LOCATION;
  1065. for (Index = 0; Index < DW_GOOD_COUNT; Index += 1) {
  1066. Context->Inventory[Index] = 0;
  1067. }
  1068. DwDrawGameBoard(Context);
  1069. return;
  1070. }
  1071. VOID
  1072. DwDrawGameBoard (
  1073. PDW_CONTEXT Context
  1074. )
  1075. /*++
  1076. Routine Description:
  1077. This routine draws the static and initial components of the game board.
  1078. Arguments:
  1079. Context - Supplies a pointer to the application context.
  1080. Return Value:
  1081. None.
  1082. --*/
  1083. {
  1084. INT Row;
  1085. SwClearRegion(ConsoleColorGray, ConsoleColorDefault, 0, 0, 80, 25);
  1086. SwClearRegion(ConsoleColorDarkBlue, ConsoleColorDefault, 1, 1, 78, 16);
  1087. SwMoveCursor(stdout, 3, 0);
  1088. SwPrintInColor(ConsoleColorGray,
  1089. ConsoleColorDarkBlue,
  1090. "%02d-01-19%02d",
  1091. DwRandom(1, 12),
  1092. DwRandom(60, 91));
  1093. SwMoveCursor(stdout, 65, 0);
  1094. SwPrintInColor(ConsoleColorGray, ConsoleColorDarkBlue, "Space 100");
  1095. SwMoveCursor(stdout, 1, 1);
  1096. SwPrintInColor(ConsoleColorDarkBlue,
  1097. ConsoleColorGray,
  1098. DwString(DwsHorizontalLine));
  1099. SwMoveCursor(stdout, 1, 2);
  1100. SwPrintInColor(ConsoleColorDarkBlue,
  1101. ConsoleColorGray,
  1102. DwString(DwsColumnTitles));
  1103. SwMoveCursor(stdout, 1, 3);
  1104. SwPrintInColor(ConsoleColorDarkBlue,
  1105. ConsoleColorGray,
  1106. DwString(DwsHorizontalLine));
  1107. for (Row = 4; Row < 16; Row += 1) {
  1108. SwMoveCursor(stdout, 1, Row);
  1109. SwPrintInColor(ConsoleColorDarkBlue,
  1110. ConsoleColorGray,
  1111. DwString(DwsTwoColumnLine));
  1112. }
  1113. SwMoveCursor(stdout, 1, 16);
  1114. SwPrintInColor(ConsoleColorDarkBlue,
  1115. ConsoleColorGray,
  1116. DwString(DwsHorizontalLine));
  1117. DwRedrawCash(Context);
  1118. DwRedrawWeapons(Context);
  1119. DwRedrawHealth(Context);
  1120. DwRedrawBank(Context);
  1121. DwRedrawDebt(Context);
  1122. return;
  1123. }
  1124. VOID
  1125. DwPlay (
  1126. PDW_CONTEXT Context
  1127. )
  1128. /*++
  1129. Routine Description:
  1130. This routine implements the main game loop.
  1131. Arguments:
  1132. Context - Supplies a pointer to the application context.
  1133. Return Value:
  1134. None.
  1135. --*/
  1136. {
  1137. //
  1138. // Live day by day.
  1139. //
  1140. while ((Context->Health > 0) && (Context->Day <= DW_GAME_TIME) &&
  1141. (Context->ExitRequested == FALSE)) {
  1142. SwMoveCursor(stdout, 6, 0);
  1143. SwPrintInColor(ConsoleColorGray,
  1144. ConsoleColorDarkBlue,
  1145. "%02d",
  1146. Context->Day);
  1147. DwDrawLocation(DwLocationName(Context->Location));
  1148. DwDoDailyEvents(Context);
  1149. if (Context->Health <= 0) {
  1150. break;
  1151. }
  1152. DwParticipateInMarket(Context);
  1153. Context->Day += 1;
  1154. }
  1155. return;
  1156. }
  1157. VOID
  1158. DwDoDailyEvents (
  1159. PDW_CONTEXT Context
  1160. )
  1161. /*++
  1162. Routine Description:
  1163. This routine performs the daily routine, such as fetching market prices,
  1164. and meeting people on the subway.
  1165. Arguments:
  1166. Context - Supplies a pointer to the application context.
  1167. Return Value:
  1168. None.
  1169. --*/
  1170. {
  1171. INT Chance;
  1172. INT Index;
  1173. CHAR Line[240];
  1174. INT Price;
  1175. PSTR Qualifier;
  1176. PSTR SurgeFormat;
  1177. INT Worth;
  1178. //
  1179. // Go through the regular chores every day except the first.
  1180. //
  1181. if (Context->Day != 1) {
  1182. //
  1183. // Update the loan shark and bank on another day.
  1184. //
  1185. if (Context->Debt != 0) {
  1186. Context->Debt =
  1187. (Context->Debt * (DW_LOAN_INTEREST_RATE + 100)) / 100;
  1188. DwRedrawDebt(Context);
  1189. }
  1190. if (Context->Bank != 0) {
  1191. Context->Bank =
  1192. (Context->Bank * (DW_BANK_INTEREST_RATE + 100)) / 100;
  1193. DwRedrawBank(Context);
  1194. }
  1195. //
  1196. // Determine if something interesting is going to happen.
  1197. //
  1198. Worth = Context->Cash - Context->Debt;
  1199. Chance = 100;
  1200. if (Worth > 3000000) {
  1201. Chance = 130;
  1202. } else if (Worth > 1000000) {
  1203. Chance = 115;
  1204. }
  1205. if (DwRandom(0, Chance) > 75) {
  1206. Chance = 80 + DwLocations[Context->Location].PolicePresence;
  1207. Chance = DwRandom(0, Chance);
  1208. if (Chance < 33) {
  1209. DwReceiveOffer(Context);
  1210. } else if (Chance < 50) {
  1211. DwPerformActOfGod(Context);
  1212. } else {
  1213. DwEncounterPolice(Context);
  1214. }
  1215. }
  1216. if (Context->Health <= 0) {
  1217. return;
  1218. }
  1219. //
  1220. // Sometimes the lady on the subway pipes up.
  1221. //
  1222. if (DwRandom(0, 100) < 15) {
  1223. if (DwRandom(0, 100) < 50) {
  1224. Qualifier = "";
  1225. if (DwRandom(0, 100) < 30) {
  1226. Qualifier = DwString(DwsSubwayQualifier);
  1227. }
  1228. Index = DwRandom(0, DW_SUBWAY_SAYINGS_COUNT);
  1229. snprintf(Line,
  1230. sizeof(Line),
  1231. DwString(DwsSubwayLadyFormat),
  1232. DwString(DwsSubwaySayings + Index),
  1233. Qualifier);
  1234. } else {
  1235. Index = DwRandom(0, DW_SONG_COUNT);
  1236. snprintf(Line,
  1237. sizeof(Line),
  1238. DwString(DwsHearSongFormat),
  1239. DwString(DwsSongs + Index));
  1240. }
  1241. }
  1242. //
  1243. // In a certain part of town, it's possible to visit some special folks.
  1244. //
  1245. if (Context->Location == DW_FINANCIAL_DISTRICT) {
  1246. DwVisitFinancialDistrict(Context);
  1247. }
  1248. }
  1249. //
  1250. // Go get today's market prices, and note any large price fluctuations.
  1251. //
  1252. DwGenerateMarket(Context);
  1253. for (Index = 0; Index < DW_GOOD_COUNT; Index += 1) {
  1254. Price = Context->Market[Index];
  1255. //
  1256. // If the good is not in the market or has a normal price, then ignore
  1257. // it.
  1258. //
  1259. if ((Price == 0) ||
  1260. ((Price >= DwGoods[Index].MinPrice) &&
  1261. (Price < DwGoods[Index].MaxPrice))) {
  1262. continue;
  1263. }
  1264. //
  1265. // Everyone loves a sale.
  1266. //
  1267. if (Price < DwGoods[Index].MinPrice) {
  1268. DwPresentNotification(Context, DwString(DwsGoodsSales + Index));
  1269. //
  1270. // A surge: help a brother out.
  1271. //
  1272. } else {
  1273. if (DwRandom(0, 100) < 50) {
  1274. SurgeFormat = DwString(DwsSurgeFormat1);
  1275. } else {
  1276. SurgeFormat = DwString(DwsSurgeFormat2);
  1277. }
  1278. snprintf(Line, sizeof(Line), SurgeFormat, DwGoodName(Index));
  1279. DwPresentNotification(Context, Line);
  1280. }
  1281. }
  1282. return;
  1283. }
  1284. VOID
  1285. DwReceiveOffer (
  1286. PDW_CONTEXT Context
  1287. )
  1288. /*++
  1289. Routine Description:
  1290. This routine gives the player a special product offer.
  1291. Arguments:
  1292. Context - Supplies a pointer to the application context.
  1293. Return Value:
  1294. None.
  1295. --*/
  1296. {
  1297. INT Answer;
  1298. CHAR Line[80];
  1299. INT Price;
  1300. INT Product;
  1301. //
  1302. // Potentially offer the player more space for goods.
  1303. //
  1304. if (DwRandom(0, 100) < 50) {
  1305. Price = DwRandom(DW_MIN_SPACE_PRICE, DW_MAX_SPACE_PRICE);
  1306. if (Price <= Context->Cash) {
  1307. snprintf(Line,
  1308. sizeof(Line),
  1309. DwString(DwsProductOfferFormat),
  1310. DwString(DwsProductMoreSpace),
  1311. Price);
  1312. Answer = DwReadYesNoAnswer(Context, NULL, Line);
  1313. if (Answer == 1) {
  1314. Context->Space += DwRandom(1, 2) * DW_MORE_SPACE;
  1315. Context->Cash -= Price;
  1316. DwRedrawSpace(Context);
  1317. DwRedrawCash(Context);
  1318. }
  1319. }
  1320. //
  1321. // Offer the player a weapon.
  1322. //
  1323. } else {
  1324. Product = DwRandom(0, DW_WEAPON_COUNT);
  1325. Price = DwWeapons[Product].Price;
  1326. if ((Price <= Context->Cash) &&
  1327. (Context->Space >= DwWeapons[Product].Space)) {
  1328. snprintf(Line,
  1329. sizeof(Line),
  1330. DwString(DwsProductOfferFormat),
  1331. DwWeaponName(Product),
  1332. DwWeapons[Product].Price);
  1333. Answer = DwReadYesNoAnswer(Context, NULL, Line);
  1334. if (Answer == 1) {
  1335. Context->Space -= DwWeapons[Product].Space;
  1336. Context->WeaponCount += 1;
  1337. Context->WeaponDamage += DwWeapons[Product].Damage;
  1338. Context->Cash -= Price;
  1339. DwRedrawCash(Context);
  1340. DwRedrawSpace(Context);
  1341. DwRedrawWeapons(Context);
  1342. }
  1343. }
  1344. }
  1345. return;
  1346. }
  1347. VOID
  1348. DwPerformActOfGod (
  1349. PDW_CONTEXT Context
  1350. )
  1351. /*++
  1352. Routine Description:
  1353. This routine performs a non-interactive and random action on the user.
  1354. Arguments:
  1355. Context - Supplies a pointer to the application context.
  1356. Return Value:
  1357. None.
  1358. --*/
  1359. {
  1360. INT Action;
  1361. INT Amount;
  1362. INT Answer;
  1363. INT Good;
  1364. INT Index;
  1365. CHAR Line[160];
  1366. //
  1367. // Some actions require a good that the player currently has in a certain
  1368. // quantity.
  1369. //
  1370. Amount = DwRandom(3, 7);
  1371. for (Index = 0; Index < 5; Index += 1) {
  1372. Good = DwRandom(0, DW_GOOD_COUNT);
  1373. if (Context->Inventory[Good] >= Amount) {
  1374. break;
  1375. }
  1376. }
  1377. if (Index == 5) {
  1378. Good = -1;
  1379. }
  1380. Action = DwRandom(0, 100);
  1381. //
  1382. // Sometimes there are muggers in the subway.
  1383. //
  1384. if (Action < 10) {
  1385. DwPresentNotification(Context, DwString(DwsMugged));
  1386. Context->Cash = (Context->Cash * DwRandom(80, 95)) / 100;
  1387. DwRedrawCash(Context);
  1388. //
  1389. // Sometimes gifts are given or received.
  1390. //
  1391. } else if (Action < 30) {
  1392. if (Good == -1) {
  1393. //
  1394. // Players lose out if they don't have space to receive gifts.
  1395. //
  1396. if (Amount > Context->Space) {
  1397. Amount = 0;
  1398. }
  1399. Good = DwRandom(0, DW_GOOD_COUNT);
  1400. snprintf(Line,
  1401. sizeof(Line),
  1402. DwString(DwsReceiveGiftFormat),
  1403. DwGoodName(Good));
  1404. Context->Inventory[Good] += Amount;
  1405. Context->Space -= Amount;
  1406. //
  1407. // Well heeled players give gifts to others.
  1408. //
  1409. } else {
  1410. snprintf(Line,
  1411. sizeof(Line),
  1412. DwString(DwsSendGiftFormat),
  1413. DwGoodName(Good));
  1414. Context->Inventory[Good] -= Amount;
  1415. Context->Space += Amount;
  1416. }
  1417. if (Amount != 0) {
  1418. DwPresentNotification(Context, Line);
  1419. DwRedrawSpace(Context);
  1420. DwRedrawInventory(Context);
  1421. }
  1422. //
  1423. // Sometimes people just lose things, or find things.
  1424. //
  1425. } else if (Action < 50) {
  1426. if (Good != -1) {
  1427. snprintf(Line,
  1428. sizeof(Line),
  1429. DwString(DwsLostGoodsFormat),
  1430. DwRandom(3, 7));
  1431. Context->Inventory[Good] -= Amount;
  1432. Context->Space += Amount;
  1433. } else {
  1434. if (Amount > Context->Space) {
  1435. Amount = 0;
  1436. }
  1437. Good = DwRandom(0, DW_GOOD_COUNT);
  1438. snprintf(Line,
  1439. sizeof(Line),
  1440. DwString(DwsFoundGoodsFormat),
  1441. Amount,
  1442. DwGoodName(Good));
  1443. Context->Inventory[Good] += Amount;
  1444. Context->Space -= Amount;
  1445. }
  1446. if (Amount != 0) {
  1447. DwPresentNotification(Context, Line);
  1448. DwRedrawSpace(Context);
  1449. DwRedrawInventory(Context);
  1450. }
  1451. //
  1452. // Sometimes other people share your items.
  1453. //
  1454. } else if ((Action < 60) &&
  1455. ((Context->Inventory[DW_BROWNIE_GOOD1] != 0) ||
  1456. (Context->Inventory[DW_BROWNIE_GOOD2] != 0))) {
  1457. Good = DW_BROWNIE_GOOD1;
  1458. if (Context->Inventory[DW_BROWNIE_GOOD2] >
  1459. Context->Inventory[DW_BROWNIE_GOOD1]) {
  1460. Good = DW_BROWNIE_GOOD2;
  1461. }
  1462. Amount = DwRandom(2, 6);
  1463. if (Amount > Context->Inventory[Good]) {
  1464. Amount = Context->Inventory[Good];
  1465. }
  1466. snprintf(Line,
  1467. sizeof(Line),
  1468. DwString(DwsSharedGoodsFormat),
  1469. DwGoodName(Good));
  1470. Context->Inventory[Good] -= Amount;
  1471. Context->Space += Amount;
  1472. DwPresentNotification(Context, Line);
  1473. DwRedrawSpace(Context);
  1474. DwRedrawInventory(Context);
  1475. //
  1476. // Sometimes there's that offer that's just too good to be true.
  1477. //
  1478. } else if (Action < 65) {
  1479. Answer = DwReadYesNoAnswer(Context,
  1480. DwString(DwsSirenSong),
  1481. DwString(DwsSirenPrompt));
  1482. if (Answer == 1) {
  1483. SwPrintInColor(ConsoleColorGray, ConsoleColorBlack, "Y");
  1484. SwMoveCursor(stdout, 1, 21);
  1485. SwPrintInColor(ConsoleColorGray,
  1486. ConsoleColorBlack,
  1487. DwString(DwsSirenResult));
  1488. DwPresentNotification(Context, NULL);
  1489. Context->Health = 0;
  1490. }
  1491. //
  1492. // Occasionally the player just needs to take a break from the hustle to
  1493. // sit and think.
  1494. //
  1495. } else {
  1496. Index = DwRandom(0, DW_PASSIVE_ACTIVITY_COUNT);
  1497. snprintf(Line,
  1498. sizeof(Line),
  1499. DwString(DwsPassiveActivityFormat),
  1500. DwString(DwsPassiveActivities + Index));
  1501. DwPresentNotification(Context, Line);
  1502. Amount = DwRandom(1, 10);
  1503. if (Context->Cash >= Amount) {
  1504. Context->Cash -= Amount;
  1505. }
  1506. DwRedrawCash(Context);
  1507. }
  1508. return;
  1509. }
  1510. VOID
  1511. DwEncounterPolice (
  1512. PDW_CONTEXT Context
  1513. )
  1514. /*++
  1515. Routine Description:
  1516. This routine is called when the player has a brush with the law.
  1517. Arguments:
  1518. Context - Supplies a pointer to the application context.
  1519. Return Value:
  1520. None.
  1521. --*/
  1522. {
  1523. INT Answer;
  1524. PSTR Choices;
  1525. INT Damage;
  1526. INT Defence;
  1527. INT DoctorCost;
  1528. INT Enemies;
  1529. INT FancyFeet;
  1530. INT MaxEnemies;
  1531. INT Offense;
  1532. PSTR Prompt;
  1533. INT Row;
  1534. PSTR ShotResult;
  1535. INT VictoryCash;
  1536. //
  1537. // How bad could this be?
  1538. //
  1539. MaxEnemies = 4;
  1540. if (Context->Day >= 15) {
  1541. MaxEnemies = 6;
  1542. if (Context->Day > 23) {
  1543. MaxEnemies = 9;
  1544. }
  1545. }
  1546. Enemies = DwRandom(2, MaxEnemies);
  1547. MaxEnemies = Enemies;
  1548. //
  1549. // Loop handlin' bad guys.
  1550. //
  1551. while (Enemies != 0) {
  1552. DwClearLowerRegion();
  1553. Row = 18;
  1554. SwMoveCursor(stdout, 1, Row);
  1555. SwPrintInColor(ConsoleColorGray,
  1556. ConsoleColorBlack,
  1557. DwString(DwsFightThreatFormat),
  1558. Enemies - 1);
  1559. Row += 1;
  1560. SwMoveCursor(stdout, 1, Row);
  1561. if (Context->WeaponCount != 0) {
  1562. Prompt = DwString(DwsRunOrFight);
  1563. Choices = "rf";
  1564. } else {
  1565. Prompt = DwString(DwsRunOption);
  1566. Choices = "yn";
  1567. }
  1568. SwPrintInColor(ConsoleColorGray, ConsoleColorDarkMagenta, Prompt);
  1569. Answer = DwReadCharacterSet(Context, Choices);
  1570. if (Answer == EOF) {
  1571. return;
  1572. }
  1573. //
  1574. // Fight on, player.
  1575. //
  1576. if (Answer == 'f') {
  1577. SwPrintInColor(ConsoleColorGray,
  1578. ConsoleColorBlack,
  1579. DwString(DwsFight));
  1580. Row += 1;
  1581. DwFlashText(Context,
  1582. DwString(DwsPlayerFire),
  1583. 1,
  1584. Row,
  1585. ConsoleColorGray,
  1586. ConsoleColorBlack,
  1587. ConsoleColorWhite,
  1588. FALSE);
  1589. Offense = 50 + Context->WeaponDamage;
  1590. ShotResult = DwString(DwsPlayerMissed);
  1591. if (DwRandom(0, 100) < Offense) {
  1592. Enemies -= 1;
  1593. ShotResult = DwString(DwsPlayerHit);
  1594. }
  1595. SwPrintInColor(ConsoleColorGray, ConsoleColorBlack, ShotResult);
  1596. //
  1597. // Flee from the police!
  1598. //
  1599. } else if ((Answer == 'y') || (Answer == 'r')) {
  1600. SwPrintInColor(ConsoleColorGray,
  1601. ConsoleColorBlack,
  1602. DwString(DwsRun));
  1603. Row += 1;
  1604. SwMoveCursor(stdout, 1, Row);
  1605. FancyFeet = 65 - (Enemies * 5);
  1606. if (DwRandom(0, 100) < FancyFeet) {
  1607. SwPrintInColor(ConsoleColorGray,
  1608. ConsoleColorBlack,
  1609. DwString(DwsFled));
  1610. DwPresentNotification(Context, NULL);
  1611. break;
  1612. } else {
  1613. SwPrintInColor(ConsoleColorGray,
  1614. ConsoleColorBlack,
  1615. DwString(DwsFailedToFlee));
  1616. }
  1617. //
  1618. // Just stand around and hope nothing happens.
  1619. //
  1620. } else {
  1621. Row += 1;
  1622. SwMoveCursor(stdout, 1, Row);
  1623. SwPrintInColor(ConsoleColorGray,
  1624. ConsoleColorBlack,
  1625. DwString(DwsNotFleeing));
  1626. }
  1627. Row += 1;
  1628. //
  1629. // If there are still enemies, they fire at our hero.
  1630. //
  1631. if (Enemies != 0) {
  1632. SwMoveCursor(stdout, 1, Row);
  1633. DwFlashText(Context,
  1634. DwString(DwsPlayerUnderFire),
  1635. 1,
  1636. Row,
  1637. ConsoleColorGray,
  1638. ConsoleColorBlack,
  1639. ConsoleColorWhite,
  1640. FALSE);
  1641. Defence = 60 - (Enemies * 5);
  1642. if (DwRandom(0, 100) < Defence) {
  1643. SwPrintInColor(ConsoleColorGray,
  1644. ConsoleColorBlack,
  1645. DwString(DwsTheyMissed));
  1646. } else {
  1647. SwPrintInColor(ConsoleColorGray,
  1648. ConsoleColorBlack,
  1649. DwString(DwsTheyHit));
  1650. Damage = DwRandom(5, 10);
  1651. if (Damage >= Context->Health) {
  1652. Context->Health = 0;
  1653. } else {
  1654. Context->Health -= Damage;
  1655. }
  1656. }
  1657. DwRedrawHighlightedHealth(Context);
  1658. if (Context->Health <= 0) {
  1659. Row += 1;
  1660. SwMoveCursor(stdout, 1, Row);
  1661. SwPrintInColor(ConsoleColorGray,
  1662. ConsoleColorBlack,
  1663. DwString(DwsKilled));
  1664. }
  1665. DwPresentNotification(Context, NULL);
  1666. DwRedrawHealth(Context);
  1667. if (Context->Health <= 0) {
  1668. break;
  1669. }
  1670. //
  1671. // Victory!
  1672. //
  1673. } else {
  1674. DwPresentNotification(Context, NULL);
  1675. SwClearRegion(ConsoleColorGray, ConsoleColorDefault, 0, 24, 80, 1);
  1676. VictoryCash = DwRandom(1000, 1500 + (MaxEnemies * 200));
  1677. SwMoveCursor(stdout, 1, Row);
  1678. SwPrintInColor(ConsoleColorGray,
  1679. ConsoleColorBlack,
  1680. DwString(DwsFightVictoryFormat),
  1681. VictoryCash);
  1682. Context->Cash += VictoryCash;
  1683. DoctorCost = DwRandom(100, 200) *
  1684. (DW_INITIAL_HEALTH - Context->Health) / 5;
  1685. if (DoctorCost > Context->Cash) {
  1686. DoctorCost = Context->Cash;
  1687. }
  1688. if (DoctorCost != 0) {
  1689. SwPrintInColor(ConsoleColorGray,
  1690. ConsoleColorDarkMagenta,
  1691. DwString(DwsDoctorOffer),
  1692. DoctorCost);
  1693. Answer = DwReadYesNoAnswer(Context, NULL, NULL);
  1694. if (Answer == EOF) {
  1695. return;
  1696. }
  1697. if (Answer == 1) {
  1698. Context->Cash -= DoctorCost;
  1699. Context->Health = DW_INITIAL_HEALTH;
  1700. }
  1701. } else {
  1702. DwPresentNotification(Context, NULL);
  1703. }
  1704. DwRedrawCash(Context);
  1705. DwRedrawHealth(Context);
  1706. break;
  1707. }
  1708. }
  1709. return;
  1710. }
  1711. VOID
  1712. DwVisitFinancialDistrict (
  1713. PDW_CONTEXT Context
  1714. )
  1715. /*++
  1716. Routine Description:
  1717. This routine is called to prompt the user and handle visits to the bank and
  1718. potentially the loan shark.
  1719. Arguments:
  1720. Context - Supplies a pointer to the application context.
  1721. Return Value:
  1722. None.
  1723. --*/
  1724. {
  1725. INT Action;
  1726. INT Answer;
  1727. INT Value;
  1728. //
  1729. // Visit the loan shark if the player has a loan.
  1730. //
  1731. if (Context->Debt != 0) {
  1732. Answer = DwReadYesNoAnswer(Context, NULL, DwString(DwsVisitLoanShark));
  1733. if (Answer == -1) {
  1734. return;
  1735. }
  1736. if (Answer == 1) {
  1737. SwPrintInColor(ConsoleColorGray,
  1738. ConsoleColorBlack,
  1739. DwString(DwsYes));
  1740. SwMoveCursor(stdout, 1, 20);
  1741. SwPrintInColor(ConsoleColorGray,
  1742. ConsoleColorDarkMagenta,
  1743. DwString(DwsLoanRepaymentAmount));
  1744. Value = DwReadQuantity(Context);
  1745. if (Value > 0) {
  1746. if ((Value <= Context->Cash) && (Value <= Context->Debt)) {
  1747. Context->Cash -= Value;
  1748. Context->Debt -= Value;
  1749. DwRedrawCash(Context);
  1750. if (Context->Debt == 0) {
  1751. SwClearRegion(ConsoleColorDarkBlue,
  1752. ConsoleColorDefault,
  1753. 9,
  1754. 13,
  1755. 20,
  1756. 1);
  1757. } else {
  1758. DwRedrawDebt(Context);
  1759. }
  1760. }
  1761. }
  1762. }
  1763. }
  1764. //
  1765. // Visit the bank.
  1766. //
  1767. Answer = DwReadYesNoAnswer(Context, NULL, DwString(DwsVisitBank));
  1768. if (Answer == -1) {
  1769. return;
  1770. }
  1771. if (Answer == 1) {
  1772. SwPrintInColor(ConsoleColorGray, ConsoleColorBlack, DwString(DwsYes));
  1773. SwMoveCursor(stdout, 1, 19);
  1774. SwPrintInColor(ConsoleColorGray,
  1775. ConsoleColorDarkMagenta,
  1776. DwString(DwsDepositOrWithdraw));
  1777. Action = DwReadCharacterSet(Context, "dw");
  1778. if (Action == -1) {
  1779. return;
  1780. }
  1781. SwPrintInColor(ConsoleColorGray,
  1782. ConsoleColorBlack,
  1783. "%c",
  1784. toupper(Action));
  1785. SwMoveCursor(stdout, 1, 20);
  1786. SwPrintInColor(ConsoleColorGray,
  1787. ConsoleColorDarkMagenta,
  1788. DwString(DwsHowMuchMoney));
  1789. Value = DwReadQuantity(Context);
  1790. if (Value > 0) {
  1791. if (Action == 'd') {
  1792. if (Value <= Context->Cash) {
  1793. Context->Cash -= Value;
  1794. Context->Bank += Value;
  1795. }
  1796. } else if (Action == 'w') {
  1797. if (Value <= Context->Bank) {
  1798. Context->Cash += Value;
  1799. Context->Bank -= Value;
  1800. }
  1801. }
  1802. DwRedrawBank(Context);
  1803. DwRedrawCash(Context);
  1804. }
  1805. }
  1806. return;
  1807. }
  1808. VOID
  1809. DwGenerateMarket (
  1810. PDW_CONTEXT Context
  1811. )
  1812. /*++
  1813. Routine Description:
  1814. This routine generates a new market's worth of goods and prices.
  1815. Arguments:
  1816. Context - Supplies a pointer to the application context.
  1817. Return Value:
  1818. None.
  1819. --*/
  1820. {
  1821. INT EventCount;
  1822. INT GoodsCount;
  1823. INT Index;
  1824. INT TotalGoodsCount;
  1825. for (Index = 0; Index < DW_GOOD_COUNT; Index += 1) {
  1826. Context->Market[Index] = 0;
  1827. }
  1828. //
  1829. // Determine how many special events will occur today.
  1830. //
  1831. EventCount = 0;
  1832. if (DwRandom(0, 100) < 70) {
  1833. EventCount = 1;
  1834. if (DwRandom(0, 100) < 40) {
  1835. EventCount = 2;
  1836. if (DwRandom(0, 100) < 5) {
  1837. EventCount = 3;
  1838. }
  1839. }
  1840. }
  1841. //
  1842. // Determine what those special events are.
  1843. //
  1844. GoodsCount = 0;
  1845. while (EventCount > 0) {
  1846. Index = DwRandom(0, DW_GOOD_COUNT);
  1847. if (Context->Market[Index] != 0) {
  1848. continue;
  1849. }
  1850. if ((DwGoods[Index].Surges == FALSE) &&
  1851. (DwGoods[Index].Sales == FALSE)) {
  1852. continue;
  1853. }
  1854. GoodsCount += 1;
  1855. EventCount -= 1;
  1856. Context->Market[Index] = DwRandom(DwGoods[Index].MinPrice,
  1857. DwGoods[Index].MaxPrice);
  1858. if (DwGoods[Index].Surges != FALSE) {
  1859. Context->Market[Index] *= DW_SURGE_FACTOR;
  1860. } else if (DwGoods[Index].Sales != FALSE) {
  1861. Context->Market[Index] /= DW_SALE_FACTOR;
  1862. }
  1863. }
  1864. //
  1865. // Determine how many goods will be in the market.
  1866. //
  1867. TotalGoodsCount = DwRandom(DwLocations[Context->Location].MinGoods,
  1868. DwLocations[Context->Location].MaxGoods);
  1869. assert(TotalGoodsCount <= DW_GOOD_COUNT);
  1870. GoodsCount = TotalGoodsCount - GoodsCount;
  1871. while (GoodsCount > 0) {
  1872. Index = DwRandom(0, DW_GOOD_COUNT);
  1873. if (Context->Market[Index] != 0) {
  1874. continue;
  1875. }
  1876. Context->Market[Index] = DwRandom(DwGoods[Index].MinPrice,
  1877. DwGoods[Index].MaxPrice);
  1878. GoodsCount -= 1;
  1879. }
  1880. return;
  1881. }
  1882. VOID
  1883. DwParticipateInMarket (
  1884. PDW_CONTEXT Context
  1885. )
  1886. /*++
  1887. Routine Description:
  1888. This routine is where the player buys and sells goods.
  1889. Arguments:
  1890. Context - Supplies a pointer to the application context.
  1891. Return Value:
  1892. None.
  1893. --*/
  1894. {
  1895. INT Action;
  1896. INT Choice;
  1897. CHAR ChoiceBuffer[DW_GOOD_COUNT + 1];
  1898. PSTR Choices;
  1899. INT Index;
  1900. INT MaxQuantity;
  1901. PSTR Prompt;
  1902. INT Quantity;
  1903. INT SelectedGood;
  1904. while (Context->ExitRequested == FALSE) {
  1905. DwDrawMarket(Context);
  1906. //
  1907. // Determine if the user has anything in inventory, and can therefore
  1908. // sell.
  1909. //
  1910. Choices = "bj";
  1911. Prompt = DwString(DwsBuyOrJet);
  1912. for (Index = 0; Index < DW_GOOD_COUNT; Index += 1) {
  1913. if (Context->Inventory[Index] != 0) {
  1914. Choices = "bsj";
  1915. Prompt = DwString(DwsBuySellJet);
  1916. break;
  1917. }
  1918. }
  1919. DwDrawBottomPrompt(Prompt);
  1920. Action = DwReadCharacterSet(Context, Choices);
  1921. if (Action == EOF) {
  1922. break;
  1923. }
  1924. if ((Action == 'b') || (Action == 's')) {
  1925. SwClearRegion(ConsoleColorGray, ConsoleColorDefault, 0, 24, 80, 1);
  1926. SwMoveCursor(stdout, 1, 23);
  1927. if (Action == 'b') {
  1928. SwPrintInColor(ConsoleColorGray,
  1929. ConsoleColorDarkMagenta,
  1930. DwString(DwsWhatToBuy));
  1931. } else {
  1932. SwPrintInColor(ConsoleColorGray,
  1933. ConsoleColorDarkMagenta,
  1934. DwString(DwsWhatToSell));
  1935. }
  1936. //
  1937. // Create the set of possibilities. For buying, anything in the
  1938. // market is a valid choice. For selling, anything in inventory
  1939. // is a valid choice.
  1940. //
  1941. Choice = 'a';
  1942. Choices = ChoiceBuffer;
  1943. for (Index = 0; Index < DW_GOOD_COUNT; Index += 1) {
  1944. if (Context->Market[Index] != 0) {
  1945. if ((Action == 'b') || (Context->Inventory[Index] != 0)) {
  1946. *Choices = Choice;
  1947. Choices += 1;
  1948. }
  1949. Choice += 1;
  1950. }
  1951. }
  1952. *Choices = '\0';
  1953. Choice = DwReadCharacterSet(Context, ChoiceBuffer);
  1954. if (Choice == EOF) {
  1955. break;
  1956. }
  1957. //
  1958. // Translate back to figure out which good they were talking about.
  1959. //
  1960. Choice -= 'a';
  1961. SelectedGood = 0;
  1962. for (Index = 0; Index < DW_GOOD_COUNT; Index += 1) {
  1963. if (Context->Market[Index] != 0) {
  1964. if (Choice == SelectedGood) {
  1965. SelectedGood = Index;
  1966. break;
  1967. }
  1968. SelectedGood += 1;
  1969. }
  1970. }
  1971. SwPrintInColor(ConsoleColorGray,
  1972. ConsoleColorBlack,
  1973. DwGoodName(SelectedGood));
  1974. //
  1975. // Ask how many they'd like to purchase or sell.
  1976. //
  1977. SwMoveCursor(stdout, 1, 24);
  1978. if (Action == 'b') {
  1979. MaxQuantity = Context->Cash / Context->Market[Index];
  1980. SwPrintInColor(ConsoleColorGray,
  1981. ConsoleColorDarkMagenta,
  1982. DwString(DwsHowManyToBuy),
  1983. MaxQuantity);
  1984. } else {
  1985. MaxQuantity = Context->Inventory[Index];
  1986. SwPrintInColor(ConsoleColorGray,
  1987. ConsoleColorDarkMagenta,
  1988. DwString(DwsHowManyToSell),
  1989. MaxQuantity);
  1990. }
  1991. Quantity = DwReadQuantity(Context);
  1992. //
  1993. // Do the deal. The check for space is only needed when buying.
  1994. //
  1995. if ((Quantity > 0) && (Quantity <= MaxQuantity) &&
  1996. ((Action == 's') || (Quantity <= Context->Space))) {
  1997. //
  1998. // Selling is really just buying negative quantities. Chew on
  1999. // that.
  2000. //
  2001. if (Action == 's') {
  2002. Quantity = -Quantity;
  2003. }
  2004. Context->Inventory[SelectedGood] += Quantity;
  2005. Context->Cash -= Quantity * Context->Market[SelectedGood];
  2006. Context->Space -= Quantity;
  2007. DwRedrawCash(Context);
  2008. DwRedrawInventory(Context);
  2009. DwRedrawSpace(Context);
  2010. }
  2011. //
  2012. // They're outta here.
  2013. //
  2014. } else if (Action == 'j') {
  2015. DwClearLowerRegion();
  2016. for (Index = 0; Index < DW_LOCATION_COUNT; Index += 1) {
  2017. SwMoveCursor(stdout, 4 + ((Index % 3) * 28), 18 + (Index / 3));
  2018. SwPrintInColor(ConsoleColorGray,
  2019. ConsoleColorBlack,
  2020. "%d. %s",
  2021. Index + 1,
  2022. DwLocationName(Index));
  2023. }
  2024. DwDrawBottomPrompt(DwString(DwsWhereTo));
  2025. Choice = DwReadCharacterSet(Context, "123456");
  2026. if (Choice == EOF) {
  2027. return;
  2028. }
  2029. //
  2030. // If they want a different place than they are, then ride the
  2031. // subway away from here.
  2032. //
  2033. Choice -= '1';
  2034. if (Choice != Context->Location) {
  2035. assert(Choice < DW_LOCATION_COUNT);
  2036. Context->Location = Choice;
  2037. DwClearLowerRegion();
  2038. //
  2039. // Ride the subway.
  2040. //
  2041. DwDrawLocation("");
  2042. DwFlashText(Context,
  2043. DwString(DwsSubway),
  2044. 33,
  2045. 2,
  2046. ConsoleColorDarkBlue,
  2047. ConsoleColorWhite,
  2048. ConsoleColorDarkBlue,
  2049. TRUE);
  2050. DwDrawLocation(DwLocationName(Choice));
  2051. break;
  2052. }
  2053. }
  2054. }
  2055. return;
  2056. }
  2057. VOID
  2058. DwDrawMarket (
  2059. PDW_CONTEXT Context
  2060. )
  2061. /*++
  2062. Routine Description:
  2063. This routine redraws the current daily market contents.
  2064. Arguments:
  2065. Context - Supplies a pointer to the application context.
  2066. Return Value:
  2067. None.
  2068. --*/
  2069. {
  2070. INT ColumnIndex;
  2071. INT Index;
  2072. CHAR Line[16];
  2073. CHAR Price[11];
  2074. INT Row;
  2075. CHAR Selector;
  2076. DwClearLowerRegion();
  2077. Selector = 'A';
  2078. SwMoveCursor(stdout, 1, 18);
  2079. SwPrintInColor(ConsoleColorGray,
  2080. ConsoleColorBlack,
  2081. DwString(DwsMarketGreeting));
  2082. Row = 19;
  2083. ColumnIndex = 0;
  2084. for (Index = 0; Index < DW_GOOD_COUNT; Index += 1) {
  2085. if (Context->Market[Index] == 0) {
  2086. continue;
  2087. }
  2088. SwMoveCursor(stdout, 4 + (ColumnIndex * 26), Row);
  2089. snprintf(Line, sizeof(Line), "%c> %s", Selector, DwGoodName(Index));
  2090. SwPrintInColor(ConsoleColorGray, ConsoleColorBlack, Line);
  2091. DwFormatMoney(Price, sizeof(Price), Context->Market[Index]);
  2092. SwPrintInColor(ConsoleColorGray,
  2093. ConsoleColorBlack,
  2094. "%*s",
  2095. 20 - strlen(Line),
  2096. Price);
  2097. Selector += 1;
  2098. if (ColumnIndex == 2) {
  2099. ColumnIndex = 0;
  2100. Row += 1;
  2101. } else {
  2102. ColumnIndex += 1;
  2103. }
  2104. }
  2105. return;
  2106. }
  2107. VOID
  2108. DwRedrawInventory (
  2109. PDW_CONTEXT Context
  2110. )
  2111. /*++
  2112. Routine Description:
  2113. This routine redraws the player's current inventory.
  2114. Arguments:
  2115. Context - Supplies a pointer to the application context.
  2116. Return Value:
  2117. None.
  2118. --*/
  2119. {
  2120. INT Index;
  2121. INT Quantity;
  2122. INT Row;
  2123. SwClearRegion(ConsoleColorDarkBlue,
  2124. ConsoleColorDefault,
  2125. 47,
  2126. 4,
  2127. 24,
  2128. DW_GOOD_COUNT);
  2129. Row = 4;
  2130. for (Index = 0; Index < DW_GOOD_COUNT; Index += 1) {
  2131. Quantity = Context->Inventory[Index];
  2132. if (Quantity == 0) {
  2133. continue;
  2134. }
  2135. SwMoveCursor(stdout, 47, Row);
  2136. SwPrintInColor(ConsoleColorDarkBlue,
  2137. ConsoleColorGray,
  2138. DwGoodName(Index));
  2139. SwMoveCursor(stdout, 47 + 18, Row);
  2140. SwPrintInColor(ConsoleColorDarkBlue,
  2141. ConsoleColorGray,
  2142. "%6d",
  2143. Quantity);
  2144. Row += 1;
  2145. }
  2146. return;
  2147. }
  2148. VOID
  2149. DwPresentNotification (
  2150. PDW_CONTEXT Context,
  2151. PSTR Notification
  2152. )
  2153. /*++
  2154. Routine Description:
  2155. This routine presents a notification to the user in the bottom area, and
  2156. waits for them to press space.
  2157. Arguments:
  2158. Context - Supplies a pointer to the application context.
  2159. Notification - Supplies an pointer to the notification. If NULL, then the
  2160. lower screen isn't cleared, as it's assumed the notification is already
  2161. set up.
  2162. Return Value:
  2163. None.
  2164. --*/
  2165. {
  2166. if (Notification != NULL) {
  2167. DwClearLowerRegion();
  2168. SwMoveCursor(stdout, 1, 18);
  2169. SwPrintInColor(ConsoleColorGray, ConsoleColorBlack, Notification);
  2170. }
  2171. DwDrawBottomPrompt(DwString(DwsPressSpace));
  2172. DwReadCharacterSet(Context, " ");
  2173. return;
  2174. }
  2175. VOID
  2176. DwDrawBottomPrompt (
  2177. PSTR Prompt
  2178. )
  2179. /*++
  2180. Routine Description:
  2181. This routine prints a string centered in purple at the bottom of the
  2182. screen. This routine assumes the bottom line is already clear.
  2183. Arguments:
  2184. Prompt - Supplies a pointer to the string containing the prompt to print.
  2185. Return Value:
  2186. None.
  2187. --*/
  2188. {
  2189. UINTN Column;
  2190. UINTN Length;
  2191. Length = strlen(Prompt);
  2192. if (Length >= 80) {
  2193. Column = 0;
  2194. } else {
  2195. Column = 40 - (Length / 2);
  2196. }
  2197. SwMoveCursor(stdout, Column, 24);
  2198. SwPrintInColor(ConsoleColorGray, ConsoleColorDarkMagenta, Prompt);
  2199. return;
  2200. }
  2201. VOID
  2202. DwDrawStat (
  2203. PSTR Name,
  2204. INT Row,
  2205. INT Value,
  2206. BOOL Money,
  2207. CONSOLE_COLOR Foreground,
  2208. CONSOLE_COLOR Background
  2209. )
  2210. /*++
  2211. Routine Description:
  2212. This routine redraws one of the statistics on the left pane.
  2213. Arguments:
  2214. Name - Supplies a pointer to the name of the statistic.
  2215. Row - Supplies the starting row of the statistic.
  2216. Value - Supplies the value of the stat.
  2217. Money - Supplies a boolean indicating if this is a monetary value or not.
  2218. Foreground - Supplies the text color to use.
  2219. Background - Supplies the background color to use.
  2220. Return Value:
  2221. None.
  2222. --*/
  2223. {
  2224. CHAR Line[21];
  2225. CHAR ValueString[21];
  2226. if (Money != FALSE) {
  2227. DwFormatMoney(ValueString, sizeof(ValueString), Value);
  2228. } else {
  2229. snprintf(ValueString, sizeof(ValueString), "%d", Value);
  2230. }
  2231. snprintf(Line, sizeof(Line), "%s%*s", Name, 20 - strlen(Name), ValueString);
  2232. SwMoveCursor(stdout, 9, Row);
  2233. SwPrintInColor(Background, Foreground, Line);
  2234. return;
  2235. }
  2236. VOID
  2237. DwDrawLocation (
  2238. PSTR Location
  2239. )
  2240. /*++
  2241. Routine Description:
  2242. This routine redraws the current location.
  2243. Arguments:
  2244. Location - Supplies the name of the location.
  2245. Return Value:
  2246. None.
  2247. --*/
  2248. {
  2249. INT Column;
  2250. INT Length;
  2251. SwClearRegion(ConsoleColorDarkBlue, ConsoleColorGray, 33, 2, 13, 1);
  2252. //
  2253. // Center the text.
  2254. //
  2255. Length = strlen(Location);
  2256. if (Length <= 14) {
  2257. Column = 39 - (Length / 2);
  2258. } else {
  2259. Column = 33;
  2260. }
  2261. SwMoveCursor(stdout, Column, 2);
  2262. SwPrintInColor(ConsoleColorDarkBlue, ConsoleColorWhite, Location);
  2263. return;
  2264. }
  2265. VOID
  2266. DwRedrawSpace (
  2267. PDW_CONTEXT Context
  2268. )
  2269. /*++
  2270. Routine Description:
  2271. This routine redraws the players remaining inventory capacity.
  2272. Arguments:
  2273. Context - Supplies a pointer to the application context.
  2274. Return Value:
  2275. None.
  2276. --*/
  2277. {
  2278. SwMoveCursor(stdout, 73, 0);
  2279. SwPrintInColor(ConsoleColorGray,
  2280. ConsoleColorDarkBlue,
  2281. "%4d",
  2282. Context->Space);
  2283. return;
  2284. }
  2285. VOID
  2286. DwFlashText (
  2287. PDW_CONTEXT Context,
  2288. PSTR String,
  2289. INT XPosition,
  2290. INT YPosition,
  2291. CONSOLE_COLOR Background,
  2292. CONSOLE_COLOR Foreground,
  2293. CONSOLE_COLOR FlashForeground,
  2294. BOOL Fast
  2295. )
  2296. /*++
  2297. Routine Description:
  2298. This routine flashes text for a little while, for an exciting visual
  2299. experience.
  2300. Arguments:
  2301. Context - Supplies a pointer to the application context.
  2302. String - Supplies a pointer to the string to flash.
  2303. XPosition - Supplies the column to draw the text at.
  2304. YPosition - Supplies the row to draw the text at.
  2305. Background - Supplies the background color.
  2306. Foreground - Supplies the initial and final foreground color.
  2307. FlashForeground - Supplies the accent foreground color.
  2308. Fast - Supplies a boolean indicating whether to flash fast or slow.
  2309. Return Value:
  2310. None.
  2311. --*/
  2312. {
  2313. INT Count;
  2314. CONSOLE_COLOR CurrentColor;
  2315. INT Delay;
  2316. INT Index;
  2317. if (Fast != FALSE) {
  2318. Delay = DW_FLASH_FAST_MICROSECONDS;
  2319. } else {
  2320. Delay = DW_FLASH_SLOW_MICROSECONDS;
  2321. }
  2322. Count = DwRandom(5, 7) | 1;
  2323. for (Index = 0; Index < Count; Index += 1) {
  2324. SwMoveCursor(stdout, XPosition, YPosition);
  2325. if ((Index & 0x1) != 0) {
  2326. CurrentColor = FlashForeground;
  2327. } else {
  2328. CurrentColor = Foreground;
  2329. }
  2330. SwPrintInColor(Background, CurrentColor, "%s", String);
  2331. SwSleep(Delay);
  2332. }
  2333. return;
  2334. }
  2335. INT
  2336. DwDisplayHighScores (
  2337. PDW_CONTEXT Context
  2338. )
  2339. /*++
  2340. Routine Description:
  2341. This routine displays the "high" scores. Oh yeah.
  2342. Arguments:
  2343. Context - Supplies a pointer to the player context.
  2344. Return Value:
  2345. 0 if the caller does not want to play again.
  2346. 1 if the caller does want to play again (yay).
  2347. -1 if the answer could not be read.
  2348. --*/
  2349. {
  2350. CHAR Amount[16];
  2351. INT Answer;
  2352. CONSOLE_COLOR Color;
  2353. struct tm *CurrentTime;
  2354. PSTR Dead;
  2355. PDW_HIGH_SCORE_ENTRY Entry;
  2356. INT Index;
  2357. CHAR Line[81];
  2358. PSTR Name;
  2359. INT PlayerValue;
  2360. INT Result;
  2361. INT Row;
  2362. BOOL Save;
  2363. DW_HIGH_SCORES Scores;
  2364. time_t Time;
  2365. Save = FALSE;
  2366. DwLoadHighScores(Context, &Scores);
  2367. //
  2368. // If the player made the high score list, ask for their name and remember
  2369. // to save the high scores list.
  2370. //
  2371. PlayerValue = Context->Cash + Context->Bank - Context->Debt;
  2372. Entry = &(Scores.Entries[DW_HIGH_SCORE_COUNT - 1]);
  2373. Name = (PSTR)(Entry->Name);
  2374. if (((Entry->Flags & DW_HIGH_SCORE_VALID) == 0) ||
  2375. (PlayerValue > Entry->Amount)) {
  2376. DwClearLowerRegion();
  2377. SwMoveCursor(stdout, 1, 18);
  2378. SwPrintInColor(ConsoleColorGray,
  2379. ConsoleColorBlack,
  2380. DwString(DwsMadeHighScores));
  2381. SwPrintInColor(ConsoleColorGray,
  2382. ConsoleColorDarkMagenta,
  2383. DwString(DwsNamePrompt));
  2384. Result = DwReadString(Context, Name, DW_HIGH_SCORE_NAME_SIZE);
  2385. if (Result != 0) {
  2386. strncpy(Name, DwString(DwsAnonymous), DW_HIGH_SCORE_NAME_SIZE);
  2387. }
  2388. Save = TRUE;
  2389. } else {
  2390. strncpy(Name, DwString(DwsYou), DW_HIGH_SCORE_NAME_SIZE);
  2391. }
  2392. //
  2393. // Add the remainder of the player's details, always to the last score.
  2394. //
  2395. Entry->Flags = DW_HIGH_SCORE_VALID | DW_HIGH_SCORE_YOU;
  2396. if (Context->Health != 0) {
  2397. Entry->Flags |= DW_HIGH_SCORE_ALIVE;
  2398. }
  2399. Entry->Amount = PlayerValue;
  2400. Time = time(NULL);
  2401. CurrentTime = localtime(&Time);
  2402. if (CurrentTime != NULL) {
  2403. Entry->Month = CurrentTime->tm_mon + 1;
  2404. Entry->Day = CurrentTime->tm_mday;
  2405. Entry->Year = CurrentTime->tm_year + 1900;
  2406. }
  2407. //
  2408. // Sort the scores now.
  2409. //
  2410. qsort(&(Scores.Entries[0]),
  2411. DW_HIGH_SCORE_COUNT,
  2412. sizeof(DW_HIGH_SCORE_ENTRY),
  2413. DwCompareHighScores);
  2414. //
  2415. // Print the high scores screen.
  2416. //
  2417. SwClearRegion(ConsoleColorDarkBlue, ConsoleColorDefault, 0, 0, 80, 25);
  2418. SwMoveCursor(stdout, 28, 0);
  2419. SwPrintInColor(ConsoleColorDarkBlue,
  2420. ConsoleColorYellow,
  2421. DwString(DwsHighScoresTitle));
  2422. Row = 4;
  2423. for (Index = 0; Index < DW_HIGH_SCORE_COUNT; Index += 1) {
  2424. Entry = &(Scores.Entries[Index]);
  2425. if ((Entry->Flags & DW_HIGH_SCORE_VALID) == 0) {
  2426. continue;
  2427. }
  2428. DwFormatMoney(Amount, sizeof(Amount), Entry->Amount);
  2429. Entry->Name[DW_HIGH_SCORE_NAME_SIZE - 1] = '\0';
  2430. Dead = "";
  2431. if ((Entry->Flags & DW_HIGH_SCORE_ALIVE) == 0) {
  2432. Dead = DwString(DwsHighScoreDead);
  2433. }
  2434. snprintf(Line,
  2435. sizeof(Line),
  2436. DwString(DwsHighScoreFormat),
  2437. Amount,
  2438. Entry->Month,
  2439. Entry->Day,
  2440. Entry->Year,
  2441. Entry->Name,
  2442. Dead);
  2443. Color = ConsoleColorGray;
  2444. if ((Entry->Flags & DW_HIGH_SCORE_YOU) != 0) {
  2445. Color = ConsoleColorWhite;
  2446. Entry->Flags &= ~DW_HIGH_SCORE_YOU;
  2447. }
  2448. SwMoveCursor(stdout, 6, Row);
  2449. SwPrintInColor(ConsoleColorDarkBlue, Color, "%s", Line);
  2450. Row += 1;
  2451. }
  2452. //
  2453. // Save the high scores file.
  2454. //
  2455. if (Save != FALSE) {
  2456. Scores.Checksum = 0;
  2457. Scores.Checksum = DwChecksum(&Scores, sizeof(DW_HIGH_SCORES));
  2458. DwHighScoresFileIo(&Scores, FALSE);
  2459. }
  2460. //
  2461. // Let's do it all again!
  2462. //
  2463. DwDrawBottomPrompt(DwString(DwsPlayAgain));
  2464. Answer = DwReadYesNoAnswer(Context, NULL, NULL);
  2465. return Answer;
  2466. }
  2467. VOID
  2468. DwLoadHighScores (
  2469. PDW_CONTEXT Context,
  2470. PDW_HIGH_SCORES Scores
  2471. )
  2472. /*++
  2473. Routine Description:
  2474. This routine loads the high scores, or initializes a new set.
  2475. Arguments:
  2476. Context - Supplies a pointer to the player context.
  2477. Scores - Supplies a pointer where the loaded stores will be returned.
  2478. Return Value:
  2479. None. If high scores could not be read, new ones will be initialized.
  2480. --*/
  2481. {
  2482. ULONG Checksum;
  2483. INT Result;
  2484. //
  2485. // Try to load the high scores and validate the CRC32.
  2486. //
  2487. Result = DwHighScoresFileIo(Scores, TRUE);
  2488. if ((Result == 0) && (Scores->Magic == DW_HIGH_SCORE_MAGIC)) {
  2489. Checksum = Scores->Checksum;
  2490. Scores->Checksum = 0;
  2491. if (DwChecksum(Scores, sizeof(DW_HIGH_SCORES)) == Checksum) {
  2492. Scores->Checksum = Checksum;
  2493. return;
  2494. }
  2495. }
  2496. //
  2497. // Either the scores didn't load or the CRC didn't match, so initialize a
  2498. // new set.
  2499. //
  2500. memset(Scores, 0, sizeof(DW_HIGH_SCORES));
  2501. Scores->Magic = DW_HIGH_SCORE_MAGIC;
  2502. return;
  2503. }
  2504. INT
  2505. DwHighScoresFileIo (
  2506. PDW_HIGH_SCORES Scores,
  2507. BOOL Load
  2508. )
  2509. /*++
  2510. Routine Description:
  2511. This routine attempts to load or save the high scores file.
  2512. Arguments:
  2513. Scores - Supplies a pointer to the high scores structure.
  2514. Load - Supplies a boolean indicating whether to load (TRUE) or store
  2515. (FALSE) the file.
  2516. Return Value:
  2517. 0 on success.
  2518. Returns an error number on failure.
  2519. --*/
  2520. {
  2521. PSTR Access;
  2522. PUCHAR Bytes;
  2523. FILE *File;
  2524. PSTR Home;
  2525. INT Index;
  2526. UCHAR Pad;
  2527. CHAR Path[256];
  2528. ssize_t Size;
  2529. Home = getenv("HOME");
  2530. if (Home == NULL) {
  2531. Home = ".";
  2532. }
  2533. snprintf(Path, sizeof(Path), "%s/.dwsco", Home);
  2534. Access = "wb";
  2535. if (Load != FALSE) {
  2536. Access = "rb";
  2537. }
  2538. File = fopen(Path, Access);
  2539. if (File == NULL) {
  2540. return errno;
  2541. }
  2542. Bytes = (PUCHAR)Scores;
  2543. if (Load != FALSE) {
  2544. Size = fread(Scores, 1, sizeof(DW_HIGH_SCORES), File);
  2545. //
  2546. // When the stakes are this high it's important to have truly
  2547. // bulletproof security.
  2548. //
  2549. Pad = 0x56;
  2550. for (Index = 0; Index < sizeof(DW_HIGH_SCORES); Index += 1) {
  2551. Bytes[Index] ^= Pad;
  2552. Pad += 1;
  2553. }
  2554. } else {
  2555. Pad = 0x56;
  2556. for (Index = 0; Index < sizeof(DW_HIGH_SCORES); Index += 1) {
  2557. Bytes[Index] ^= Pad;
  2558. Pad += 1;
  2559. }
  2560. Size = fwrite(Scores, 1, sizeof(DW_HIGH_SCORES), File);
  2561. }
  2562. fclose(File);
  2563. if (Size != sizeof(DW_HIGH_SCORES)) {
  2564. if (errno == 0) {
  2565. return -1;
  2566. }
  2567. return errno;
  2568. }
  2569. return 0;
  2570. }
  2571. int
  2572. DwCompareHighScores (
  2573. const void *LeftPointer,
  2574. const void *RightPointer
  2575. )
  2576. /*++
  2577. Routine Description:
  2578. This routine compares two high score entries.
  2579. Arguments:
  2580. LeftPointer - Supplies the left high score pointer to compare.
  2581. RightPointer - Supplies the right pointer to compare.
  2582. Return Value:
  2583. <0 if the left is less than the right.
  2584. 0 if the left is equal to the right.
  2585. >0 if the left is greater than the right.
  2586. --*/
  2587. {
  2588. PDW_HIGH_SCORE_ENTRY Left;
  2589. LONG LeftValue;
  2590. PDW_HIGH_SCORE_ENTRY Right;
  2591. LONG RightValue;
  2592. Left = (PDW_HIGH_SCORE_ENTRY)LeftPointer;
  2593. LeftValue = Left->Amount;
  2594. Right = (PDW_HIGH_SCORE_ENTRY)RightPointer;
  2595. RightValue = Right->Amount;
  2596. //
  2597. // First compare invalid entries.
  2598. //
  2599. if ((Left->Flags & DW_HIGH_SCORE_VALID) == 0) {
  2600. LeftValue = -999999999;
  2601. }
  2602. if ((Right->Flags & DW_HIGH_SCORE_VALID) == 0) {
  2603. RightValue = -999999999;
  2604. }
  2605. //
  2606. // Higher scores should be first in the list.
  2607. //
  2608. if (LeftValue < RightValue) {
  2609. return 1;
  2610. } else if (LeftValue > RightValue) {
  2611. return -1;
  2612. }
  2613. return 0;
  2614. }
  2615. VOID
  2616. DwFormatMoney (
  2617. PSTR String,
  2618. UINTN StringSize,
  2619. INT Value
  2620. )
  2621. /*++
  2622. Routine Description:
  2623. This routine prints a money value, with thousands separators.
  2624. Arguments:
  2625. String - Supplies a pointer to the output buffer.
  2626. StringSize - Supplies the size of the output buffer string in bytes.
  2627. Value - Supplies the value to print.
  2628. Return Value:
  2629. None.
  2630. --*/
  2631. {
  2632. INT Billions;
  2633. INT Millions;
  2634. INT Ones;
  2635. INT Thousands;
  2636. if (Value < 0) {
  2637. Value = -Value;
  2638. *String = '-';
  2639. String += 1;
  2640. StringSize -= 1;
  2641. }
  2642. Ones = Value;
  2643. Billions = Value / 1000000000;
  2644. Ones = Value % 1000000000;
  2645. Millions = Ones / 1000000;
  2646. Ones = Ones % 1000000;
  2647. Thousands = Ones / 1000;
  2648. Ones = Ones % 1000;
  2649. if (Billions != 0) {
  2650. snprintf(String,
  2651. StringSize,
  2652. "$%d,%03d,%03d,%03d",
  2653. Billions,
  2654. Millions,
  2655. Thousands,
  2656. Ones);
  2657. } else if (Millions != 0) {
  2658. snprintf(String,
  2659. StringSize,
  2660. "$%d,%03d,%03d",
  2661. Millions,
  2662. Thousands,
  2663. Ones);
  2664. } else if (Thousands != 0) {
  2665. snprintf(String, StringSize, "$%d,%03d", Thousands, Ones);
  2666. } else {
  2667. snprintf(String, StringSize, "$%d", Ones);
  2668. }
  2669. return;
  2670. }
  2671. INT
  2672. DwReadCharacterSet (
  2673. PDW_CONTEXT Context,
  2674. PSTR Set
  2675. )
  2676. /*++
  2677. Routine Description:
  2678. This routine reads a character from a given permissible set.
  2679. Arguments:
  2680. Context - Supplies a pointer to the application context.
  2681. Set - Supplies a pointer to a null terminated string containing the set of
  2682. acceptable characters.
  2683. Return Value:
  2684. Returns the character received on success.
  2685. -1 on read failure.
  2686. --*/
  2687. {
  2688. INT Character;
  2689. PSTR Current;
  2690. while (TRUE) {
  2691. Character = DwReadCharacter(Context);
  2692. if (Character == -1) {
  2693. break;
  2694. }
  2695. if (isupper(Character)) {
  2696. Character = tolower(Character);
  2697. }
  2698. //
  2699. // See if the character received was in the allowed set.
  2700. //
  2701. Current = Set;
  2702. while (*Current != '\0') {
  2703. if (*Current == Character) {
  2704. return Character;
  2705. }
  2706. Current += 1;
  2707. }
  2708. }
  2709. return Character;
  2710. }
  2711. INT
  2712. DwReadQuantity (
  2713. PDW_CONTEXT Context
  2714. )
  2715. /*++
  2716. Routine Description:
  2717. This routine reads a numeric quantity in from standard input.
  2718. Arguments:
  2719. Context - Supplies a pointer to the application context.
  2720. Return Value:
  2721. Returns the numeric value read in on success.
  2722. -1 on failure.
  2723. --*/
  2724. {
  2725. CHAR Buffer[9];
  2726. INT Character;
  2727. INT Index;
  2728. INT ScanIndex;
  2729. INT Value;
  2730. Index = 0;
  2731. while (TRUE) {
  2732. Character = DwReadCharacter(Context);
  2733. if (Character == EOF) {
  2734. return -1;
  2735. }
  2736. if (isdigit(Character)) {
  2737. if (Index < 8) {
  2738. Buffer[Index] = Character;
  2739. Index += 1;
  2740. SwPrintInColor(ConsoleColorGray,
  2741. ConsoleColorBlack,
  2742. "%c",
  2743. Character);
  2744. }
  2745. } else if ((Character == Context->Backspace) || (Character == '\b')) {
  2746. if (Index > 0) {
  2747. SwPrintInColor(ConsoleColorGray, ConsoleColorBlack, "\b \b");
  2748. Index -= 1;
  2749. }
  2750. } else if ((Character == '\r') || (Character == '\n')) {
  2751. break;
  2752. }
  2753. }
  2754. if (Index == 0) {
  2755. return -1;
  2756. }
  2757. Value = 0;
  2758. for (ScanIndex = 0; ScanIndex < Index; ScanIndex += 1) {
  2759. Value = (Value * 10) + (Buffer[ScanIndex] - '0');
  2760. }
  2761. return Value;
  2762. }
  2763. INT
  2764. DwReadString (
  2765. PDW_CONTEXT Context,
  2766. PSTR String,
  2767. INT StringSize
  2768. )
  2769. /*++
  2770. Routine Description:
  2771. This routine reads a generic string from standard input.
  2772. Arguments:
  2773. Context - Supplies a pointer to the application context.
  2774. String - Supplies a pointer where the string will be returned on success.
  2775. StringSize - Supplies string buffer size.
  2776. Return Value:
  2777. 0 on success.
  2778. -1 on failure.
  2779. --*/
  2780. {
  2781. INT Character;
  2782. INT Index;
  2783. Index = 0;
  2784. while (TRUE) {
  2785. Character = DwReadCharacter(Context);
  2786. if (Character == EOF) {
  2787. return -1;
  2788. }
  2789. if ((Character == Context->Backspace) || (Character == '\b')) {
  2790. if (Index > 0) {
  2791. SwPrintInColor(ConsoleColorGray, ConsoleColorBlack, "\b \b");
  2792. Index -= 1;
  2793. }
  2794. } else if ((Character == '\r') || (Character == '\n')) {
  2795. break;
  2796. } else {
  2797. if (Index < StringSize - 1) {
  2798. String[Index] = Character;
  2799. Index += 1;
  2800. SwPrintInColor(ConsoleColorGray,
  2801. ConsoleColorBlack,
  2802. "%c",
  2803. Character);
  2804. }
  2805. }
  2806. }
  2807. if (Index == 0) {
  2808. return -1;
  2809. }
  2810. String[Index] = '\0';
  2811. return 0;
  2812. }
  2813. INT
  2814. DwReadYesNoAnswer (
  2815. PDW_CONTEXT Context,
  2816. PSTR Exposition,
  2817. PSTR Prompt
  2818. )
  2819. /*++
  2820. Routine Description:
  2821. This routine reads a yes/no answer from the user.
  2822. Arguments:
  2823. Context - Supplies a pointer to the application context.
  2824. Exposition - Supplies an optional pointer to a line of black text to put
  2825. first. Most questions don't have this.
  2826. Prompt - Supplies an optional pointer to the question to ask.
  2827. Return Value:
  2828. 0 if the user said no.
  2829. 1 if the user said yes.
  2830. -1 on failure.
  2831. --*/
  2832. {
  2833. INT Answer;
  2834. INT Row;
  2835. if (Prompt != NULL) {
  2836. DwClearLowerRegion();
  2837. }
  2838. Row = 18;
  2839. if (Exposition != NULL) {
  2840. SwMoveCursor(stdout, 1, Row);
  2841. Row = 19;
  2842. SwPrintInColor(ConsoleColorGray, ConsoleColorBlack, Exposition);
  2843. }
  2844. if (Prompt != NULL) {
  2845. SwMoveCursor(stdout, 1, Row);
  2846. SwPrintInColor(ConsoleColorGray, ConsoleColorDarkMagenta, Prompt);
  2847. }
  2848. Answer = DwReadCharacterSet(Context, "yn");
  2849. if (Answer == EOF) {
  2850. return Answer;
  2851. }
  2852. if (Answer == 'y') {
  2853. return 1;
  2854. }
  2855. return 0;
  2856. }
  2857. INT
  2858. DwReadCharacter (
  2859. PDW_CONTEXT Context
  2860. )
  2861. /*++
  2862. Routine Description:
  2863. This routine reads a key from standard in.
  2864. Arguments:
  2865. Context - Supplies a pointer to the application context.
  2866. Return Value:
  2867. Returns the character received on success.
  2868. EOF on read failure or end of input.
  2869. --*/
  2870. {
  2871. INT Character;
  2872. Character = SwReadInputCharacter();
  2873. if (Character == 0x3) {
  2874. Context->ExitRequested = TRUE;
  2875. return -1;
  2876. }
  2877. return Character;
  2878. }
  2879. INT
  2880. DwRandom (
  2881. INT Minimum,
  2882. INT Maximum
  2883. )
  2884. /*++
  2885. Routine Description:
  2886. This routine gets a random value within the given range.
  2887. Arguments:
  2888. Minimum - Supplies the minimum random value.
  2889. Maximum - Supplies the maximum random value, exclusive.
  2890. Return Value:
  2891. Returns a random value between the specified minimum and maximum.
  2892. --*/
  2893. {
  2894. ssize_t BytesRead;
  2895. INT Value;
  2896. //
  2897. // Prefer the random source if it exists.
  2898. //
  2899. if (DwRandomSource >= 0) {
  2900. BytesRead = read(DwRandomSource, &Value, 2);
  2901. if (BytesRead == sizeof(Value)) {
  2902. return Minimum + (Value % (Maximum - Minimum));
  2903. }
  2904. }
  2905. return Minimum + (rand() % (Maximum - Minimum));
  2906. }
  2907. ULONG
  2908. DwChecksum (
  2909. PVOID Buffer,
  2910. ULONG Size
  2911. )
  2912. /*++
  2913. Routine Description:
  2914. This routine gets a checksum value for the high scores file.
  2915. Arguments:
  2916. Buffer - Supplies a pointer to the buffer to checksum.
  2917. Size - Supplies the size in bytes of the checksum.
  2918. Return Value:
  2919. Returns the checksum of the file.
  2920. --*/
  2921. {
  2922. PUCHAR Bytes;
  2923. ULONG Sum;
  2924. //
  2925. // Borrow an algorithm from ELF: Sum = (Sum * 33) + Byte for each byte.
  2926. //
  2927. Bytes = Buffer;
  2928. Sum = 0;
  2929. while (Size != 0) {
  2930. Sum = ((Sum << 5) + Sum) + *Bytes;
  2931. Bytes += 1;
  2932. Size -= 1;
  2933. }
  2934. return Sum;
  2935. }