ularn_winami.c 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608
  1. /* =============================================================================
  2. * PROGRAM: ularn
  3. * FILENAME: ularn_winami.c
  4. *
  5. * DESCRIPTION:
  6. * This module contains all operating system dependant code for input and
  7. * display update.
  8. * Each version of ularn should provide a different implementation of this
  9. * module.
  10. *
  11. * This is the Amiga window display and input module.
  12. *
  13. * =============================================================================
  14. * EXPORTED VARIABLES
  15. *
  16. * nonap : Set to true if no time delays are to be used.
  17. * nosignal : Set if ctrl-C is to be trapped to prevent exit.
  18. * enable_scroll : Probably superfluous
  19. * yrepcount : Repeat count for input commands.
  20. *
  21. * =============================================================================
  22. * EXPORTED FUNCTIONS
  23. *
  24. * init_app : Initialise the app
  25. * close_app : Close the app and free resources
  26. * get_normal_input : Get the next command input
  27. * get_prompt_input : Get input in response to a question
  28. * get_password_input : Get a password
  29. * get_num_input : Geta number
  30. * get_dir_input : Get a direction
  31. * set_display : Set the display mode
  32. * UpdateStatus : Update the status display
  33. * UpdateEffects : Update the effects display
  34. * UpdateStatusAndEffects : Update both status and effects display
  35. * ClearText : Clear the text output area
  36. * UlarnBeep : Make a beep
  37. * Cursor : Set the cursor location
  38. * Printc : Print a single character
  39. * Print : Print a string
  40. * Printf : Print a formatted string
  41. * Standout : Print a string is standout format
  42. * SetFormat : Set the output text format
  43. * ClearEOL : Clear to end of line
  44. * ClearEOPage : Clear to end of page
  45. * show1cell : Show 1 cell on the map
  46. * showplayer : Show the player on the map
  47. * showcell : Show the area around the player
  48. * drawscreen : Redraw the screen
  49. * draws : Redraw a section of the screen
  50. * mapeffect : Draw a directional effect
  51. * magic_effect_frames : Get the number of animation frames in a magic fx
  52. * magic_effect : Draw a frame in a magic fx
  53. * nap : Delay for a specified number of milliseconds
  54. * GetUser : Get the username and user id.
  55. *
  56. * =============================================================================
  57. */
  58. #include <stdarg.h>
  59. #include <stdio.h>
  60. #include <graphics/gfxbase.h>
  61. #include <graphics/modeid.h>
  62. #include <intuition/intuition.h>
  63. #include <intuition/intuitionbase.h>
  64. #include <intuition/screens.h>
  65. #include <proto/asl.h>
  66. #include <proto/diskfont.h>
  67. #include <proto/exec.h>
  68. #include <proto/graphics.h>
  69. #include <proto/intuition.h>
  70. #include "header.h"
  71. #include "ularn_game.h"
  72. #include "config.h"
  73. #include "dungeon.h"
  74. #include "itm.h"
  75. #include "monster.h"
  76. #include "player.h"
  77. #include "ularn_win.h"
  78. #include "ularnpc.rh"
  79. #include "ifftools.h"
  80. #include "smart_menu.h"
  81. //
  82. // Defines for windows
  83. //
  84. #define BLACK_PEN 0
  85. #define RED_PEN 1
  86. #define GREEN_PEN 2
  87. #define BLUE_PEN 3
  88. #define DARK_PEN 252
  89. #define MID_PEN 253
  90. #define LIGHT_PEN 254
  91. #define WHITE_PEN 255
  92. // Default size of the ularn window in characters
  93. #define SEPARATOR_WIDTH 8
  94. #define SEPARATOR_HEIGHT 8
  95. #define BORDER_SIZE 8
  96. /* =============================================================================
  97. * Exported variables
  98. */
  99. int nonap = 0;
  100. int nosignal = 0;
  101. char enable_scroll = 0;
  102. int yrepcount = 0;
  103. /* =============================================================================
  104. * Local variables
  105. */
  106. extern void Delay(long TickCount);
  107. #define M_NONE 0
  108. #define M_SHIFT 1
  109. #define M_CTRL 2
  110. #define M_NUMPAD 4
  111. #define M_ASCII 8
  112. #define MAX_KEY_BINDINGS 3
  113. struct KeyCodeType {
  114. int VirtKey;
  115. int ModKey;
  116. };
  117. #define NUM_DIRS 8
  118. static ActionType DirActions[NUM_DIRS] = {
  119. ACTION_MOVE_WEST, ACTION_MOVE_EAST, ACTION_MOVE_SOUTH,
  120. ACTION_MOVE_NORTH, ACTION_MOVE_NORTHEAST, ACTION_MOVE_NORTHWEST,
  121. ACTION_MOVE_SOUTHEAST, ACTION_MOVE_SOUTHWEST};
  122. /* Default keymap */
  123. /* Allow up to MAX_KEY_BINDINGS per action */
  124. static struct KeyCodeType KeyMap[ACTION_COUNT][MAX_KEY_BINDINGS] = {
  125. {{0, 0}, {0, 0}, {0, 0}}, // ACTION_NULL
  126. {{'~', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_DIAG
  127. {{'h', M_ASCII}, {0x4f, M_NONE}, {'4', M_NUMPAD}}, // ACTION_MOVE_WEST
  128. {{'H', M_ASCII},
  129. {0x4f, M_SHIFT},
  130. {'4', M_NUMPAD | M_SHIFT}}, // ACTION_RUN_WEST
  131. {{'l', M_ASCII}, {0x4e, M_NONE}, {'6', M_NUMPAD}}, // ACTION_MOVE_EAST,
  132. {{'L', M_ASCII},
  133. {0x4e, M_SHIFT},
  134. {'6', M_NUMPAD | M_SHIFT}}, // ACTION_RUN_EAST,
  135. {{'j', M_ASCII}, {0x4d, M_NONE}, {'2', M_NUMPAD}}, // ACTION_MOVE_SOUTH,
  136. {{'J', M_ASCII},
  137. {0x4d, M_SHIFT},
  138. {'2', M_NUMPAD | M_SHIFT}}, // ACTION_RUN_SOUTH,
  139. {{'k', M_ASCII}, {0x4c, M_NONE}, {'8', M_NUMPAD}}, // ACTION_MOVE_NORTH,
  140. {{'K', M_ASCII},
  141. {0x4c, M_SHIFT},
  142. {'8', M_NUMPAD | M_SHIFT}}, // ACTION_RUN_NORTH,
  143. {{'u', M_ASCII}, {'9', M_NUMPAD}, {0, 0}}, // ACTION_MOVE_NORTHEAST,
  144. {{'U', M_ASCII},
  145. {'9', M_NUMPAD | M_SHIFT},
  146. {0, 0}}, // ACTION_RUN_NORTHEAST,
  147. {{'y', M_ASCII}, {'7', M_NUMPAD}, {0, 0}}, // ACTION_MOVE_NORTHWEST,
  148. {{'Y', M_ASCII},
  149. {'7', M_NUMPAD | M_SHIFT},
  150. {0, 0}}, // ACTION_RUN_NORTHWEST,
  151. {{'n', M_ASCII}, {'3', M_NUMPAD}, {0, 0}}, // ACTION_MOVE_SOUTHEAST,
  152. {{'N', M_ASCII},
  153. {'3', M_NUMPAD | M_SHIFT},
  154. {0, 0}}, // ACTION_RUN_SOUTHEAST,
  155. {{'b', M_ASCII}, {'1', M_NUMPAD}, {0, 0}}, // ACTION_MOVE_SOUTHWEST,
  156. {{'B', M_ASCII},
  157. {'1', M_NUMPAD | M_SHIFT},
  158. {0, 0}}, // ACTION_RUN_SOUTHWEST,
  159. {{'.', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_WAIT,
  160. {{' ', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_NONE,
  161. {{'w', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_WIELD,
  162. {{'W', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_WEAR,
  163. {{'r', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_READ,
  164. {{'q', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_QUAFF,
  165. {{'d', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_DROP,
  166. {{'c', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_CAST_SPELL,
  167. {{'o', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_OPEN_DOOR,
  168. {{'C', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_CLOSE_DOOR,
  169. {{'O', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_OPEN_CHEST,
  170. {{'i', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_INVENTORY,
  171. {{'e', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_EAT_COOKIE,
  172. {{'\\', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_LIST_SPELLS,
  173. {{'?', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_HELP,
  174. {{'S', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_SAVE,
  175. {{'Z', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_TELEPORT,
  176. {{'^', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_IDENTIFY_TRAPS,
  177. {{'_', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_BECOME_CREATOR,
  178. {{'+', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_CREATE_ITEM,
  179. {{'-', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_TOGGLE_WIZARD,
  180. {{'`', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_DEBUG_MODE,
  181. {{'T', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_REMOVE_ARMOUR,
  182. {{'g', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_PACK_WEIGHT,
  183. {{'v', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_VERSION,
  184. {{'Q', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_QUIT,
  185. {{0x12, M_ASCII}, {0, 0}, {0, 0}}, // ACTION_REDRAW_SCREEN,
  186. {{'P', M_ASCII}, {0, 0}, {0, 0}} // ACTION_SHOW_TAX
  187. };
  188. static struct KeyCodeType RunKeyMap = {'5', M_NUMPAD};
  189. //
  190. // Amiga stuff
  191. //
  192. struct IntuitionBase *IntuitionBase = NULL;
  193. struct GfxBase *GfxBase = NULL;
  194. struct Library *AslBase = NULL;
  195. struct Screen *UlarnScreen = NULL;
  196. struct Window *UlarnWindow = NULL;
  197. struct RastPort *UlarnRP = NULL;
  198. static struct BitMap *UlarnGfx = NULL;
  199. static ULONG UlarnPalette[256];
  200. static struct TextAttr UlarnTextAttr = {"topaz.font", 8, 0, NULL};
  201. static struct TextFont *UlarnFont = NULL;
  202. UWORD UlarnPens[NUMDRIPENS + 1] = {
  203. 255, // DETAILPEN
  204. 253, // BLOCKPEN
  205. 255, // TEXTPEN
  206. 254, // SHINEPEN
  207. 252, // SHADOWPEN
  208. 1, // FILLPEN
  209. 2, // FILLTEXTPEN
  210. 253, // BACKGROUNDPEN
  211. 0, // HIGHLIGHTPEN
  212. 255, // BARDETAILPEN
  213. 253, // PARBLOCKPEN
  214. 252, // BARTRIMPEN
  215. 0xFFFF // Terminator
  216. };
  217. //
  218. // Variables for windows
  219. //
  220. #define INITIAL_WIDTH 400
  221. #define INITIAL_HEIGHT 300
  222. static int CaretActive = 0;
  223. static int TileWidth = 32;
  224. static int TileHeight = 32;
  225. static int CharHeight = 8;
  226. static int CharWidth = 8;
  227. static int CharBaseline = 6;
  228. static int LarnWindowLeft = 0;
  229. static int LarnWindowTop = 0;
  230. static int LarnWindowWidth = INITIAL_WIDTH;
  231. static int LarnWindowHeight = INITIAL_HEIGHT;
  232. static int LarnWindowMaximized = 0;
  233. static int MinWindowWidth;
  234. static int MinWindowHeight;
  235. static int Runkey;
  236. static ActionType Event;
  237. static int GotChar;
  238. static char EventChar;
  239. //
  240. // Smartmenu structures and handling functions.
  241. //
  242. static void DoMenuSave(void) { Event = ACTION_SAVE; }
  243. static void DoMenuQuit(void) { Event = ACTION_QUIT; }
  244. static void DoMenuWait(void) { Event = ACTION_WAIT; }
  245. static void DoMenuWield(void) { Event = ACTION_WIELD; }
  246. static void DoMenuWear(void) { Event = ACTION_WEAR; }
  247. static void DoMenuTakeoff(void) { Event = ACTION_REMOVE_ARMOUR; }
  248. static void DoMenuQuaff(void) { Event = ACTION_QUAFF; }
  249. static void DoMenuRead(void) { Event = ACTION_READ; }
  250. static void DoMenuCast(void) { Event = ACTION_CAST_SPELL; }
  251. static void DoMenuEat(void) { Event = ACTION_EAT_COOKIE; }
  252. static void DoMenuDrop(void) { Event = ACTION_DROP; }
  253. static void DoMenuClose(void) { Event = ACTION_CLOSE_DOOR; }
  254. static void DoMenuDiscoveries(void) { Event = ACTION_LIST_SPELLS; }
  255. static void DoMenuInventory(void) { Event = ACTION_INVENTORY; }
  256. static void DoMenuTax(void) { Event = ACTION_SHOW_TAX; }
  257. static void DoMenuPackweight(void) { Event = ACTION_PACK_WEIGHT; }
  258. static void DoMenuRedraw(void) { Event = ACTION_REDRAW_SCREEN; }
  259. static void DoMenuBeep(void) {
  260. if (nobeep)
  261. nobeep = 0;
  262. else
  263. nobeep = 1;
  264. }
  265. static void DoMenuHelp(void) { Event = ACTION_HELP; }
  266. static void DoMenuVersion(void) { Event = ACTION_VERSION; }
  267. static struct SmartMenuItem UlarnGameMenu[3] = {
  268. {"Save", 'S', 255, 253, DoMenuSave, NULL},
  269. {"Quit", 'Q', 255, 253, DoMenuQuit, NULL},
  270. {NULL, 0, 0, 0, NULL, NULL}};
  271. static struct SmartMenuItem UlarnCommandMenu[11] = {
  272. {"Wait", 0, 255, 253, DoMenuWait, NULL},
  273. {"Wield", 0, 255, 253, DoMenuWield, NULL},
  274. {"Wear", 0, 255, 253, DoMenuWear, NULL},
  275. {"Take off", 0, 255, 253, DoMenuTakeoff, NULL},
  276. {"Quaff", 0, 255, 253, DoMenuQuaff, NULL},
  277. {"Read", 0, 255, 253, DoMenuRead, NULL},
  278. {"Cast", 0, 255, 253, DoMenuCast, NULL},
  279. {"Eat", 0, 255, 253, DoMenuEat, NULL},
  280. {"Drop", 0, 255, 253, DoMenuDrop, NULL},
  281. {"Close", 0, 255, 253, DoMenuClose, NULL},
  282. {NULL, 0, 0, 0, NULL, NULL}};
  283. static struct SmartMenuItem UlarnShowMenu[5] = {
  284. {"Discoveries", 0, 255, 253, DoMenuDiscoveries, NULL},
  285. {"Inventory", 0, 255, 253, DoMenuInventory, NULL},
  286. {"Tax", 0, 255, 253, DoMenuTax, NULL},
  287. {"Pack weight", 0, 255, 253, DoMenuPackweight, NULL},
  288. {NULL, 0, 0, 0, NULL, NULL}};
  289. static struct SmartMenuItem UlarnDisplayMenu[3] = {
  290. {"Redraw", 0, 255, 253, DoMenuRedraw, NULL},
  291. {"Beep", 0, 255, 253, DoMenuBeep, NULL},
  292. {NULL, 0, 0, 0, NULL, NULL}};
  293. static struct SmartMenuItem UlarnHelpMenu[3] = {
  294. {"Help", 0, 255, 253, DoMenuHelp, NULL},
  295. {"Version", 0, 255, 253, DoMenuVersion, NULL},
  296. {NULL, 0, 0, 0, NULL, NULL}};
  297. static struct SmartMenu UlarnMenu[6] = {
  298. {"Game", UlarnGameMenu}, {"Commands", UlarnCommandMenu},
  299. {"Show", UlarnShowMenu}, {"Display", UlarnDisplayMenu},
  300. {"Help", UlarnHelpMenu}, {NULL, NULL}};
  301. //
  302. // player id file
  303. //
  304. static char *PIDName = LIBDIR "/vlarn.pid";
  305. #define FIRST_PID 1001
  306. //
  307. // ularn.ini file for window position & font selection
  308. //
  309. static char *IniName = "vlarn.ini";
  310. //
  311. // Bitmaps for tiles
  312. //
  313. static char *TileBMName = LIBDIR "/vlarn_gfx.iff";
  314. /* Tiles for different character classes, (female, male) */
  315. static int PlayerTiles[8][2] = {
  316. {165, 181}, /* Ogre */
  317. {166, 182}, /* Wizard */
  318. {167, 183}, /* Klingon */
  319. {168, 184}, /* Elf */
  320. {169, 185}, /* Rogue */
  321. {170, 186}, /* Adventurer */
  322. {171, 187}, /* Dwarf */
  323. {172, 188} /* Rambo */
  324. };
  325. #define TILE_CURSOR1 174
  326. #define TILE_CURSOR2 190
  327. #define WALL_TILES 352
  328. /* Tiles for directional effects */
  329. static int EffectTile[EFFECT_COUNT][9] = {
  330. {191, 198, 196, 194, 192, 195, 193, 197, 199},
  331. {191, 206, 204, 202, 200, 203, 201, 205, 207},
  332. {191, 214, 212, 210, 208, 211, 209, 213, 215},
  333. {191, 222, 220, 218, 216, 219, 217, 221, 223},
  334. {191, 230, 228, 226, 224, 227, 225, 229, 231}};
  335. #define MAX_MAGICFX_FRAME 8
  336. struct MagicEffectDataType {
  337. int Overlay; /* 0 = no overlay, 1 = overlay */
  338. int Frames; /* Number of frames in the effect */
  339. int Tile1[MAX_MAGICFX_FRAME]; /* The primary tile for this frame */
  340. int Tile2[MAX_MAGICFX_FRAME]; /* Only used for overlay effects */
  341. };
  342. static struct MagicEffectDataType magicfx_tile[MAGIC_COUNT] = {
  343. /* Sparkle */
  344. {1, /* Overlay this on current tile */
  345. 8,
  346. {240, 241, 242, 243, 244, 245, 246, 247},
  347. {248, 249, 250, 251, 252, 253, 254, 255}},
  348. /* Sleep */
  349. {0, 6, {256, 272, 288, 304, 320, 336, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  350. /* Web */
  351. {0, 6, {257, 273, 289, 305, 321, 337, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  352. /* Phantasmal forces */
  353. {0, 6, {258, 274, 290, 306, 322, 338, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  354. /* Cloud kill */
  355. {0, 6, {259, 275, 291, 307, 323, 339, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  356. /* Vaporize rock */
  357. {0, 6, {260, 276, 292, 308, 324, 340, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  358. /* Dehydrate */
  359. {0, 6, {261, 277, 293, 309, 325, 341, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  360. /* Drain life */
  361. {0, 6, {262, 278, 294, 310, 326, 342, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  362. /* Flood */
  363. {0, 6, {263, 279, 295, 311, 327, 343, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  364. /* Finger of death */
  365. {0, 6, {264, 280, 296, 312, 328, 344, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  366. /* Teleport away */
  367. {0, 6, {265, 281, 297, 313, 329, 345, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  368. /* Magic fire */
  369. {0, 6, {266, 282, 298, 314, 330, 346, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  370. /* Make wall */
  371. {0, 6, {267, 283, 299, 315, 331, 347, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  372. /* Summon demon */
  373. {0, 6, {268, 284, 300, 316, 332, 348, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  374. /* Annihilate (scroll) */
  375. {0, 6, {269, 285, 301, 317, 333, 349, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}}};
  376. //
  377. // Current display mode
  378. //
  379. DisplayModeType CurrentDisplayMode = DISPLAY_TEXT;
  380. //
  381. // Map window position and size
  382. //
  383. static int MapLeft;
  384. static int MapTop;
  385. static int MapWidth;
  386. static int MapHeight;
  387. static int MapTileLeft = 0;
  388. static int MapTileTop = 0;
  389. static int MapTileWidth;
  390. static int MapTileHeight;
  391. //
  392. // Status lines window position and size
  393. //
  394. static int StatusLeft;
  395. static int StatusTop;
  396. static int StatusWidth;
  397. static int StatusHeight;
  398. //
  399. // Effects window position and size
  400. //
  401. static int EffectsLeft;
  402. static int EffectsTop;
  403. static int EffectsWidth;
  404. static int EffectsHeight;
  405. //
  406. // Message window position and size
  407. //
  408. static int MessageLeft;
  409. static int MessageTop;
  410. static int MessageWidth;
  411. static int MessageHeight;
  412. //
  413. // Text window position, size
  414. //
  415. static int TextLeft;
  416. static int TextTop;
  417. static int TextWidth;
  418. static int TextHeight;
  419. static int ShowTextBorder;
  420. // =============================================================================
  421. // Text mode stuff
  422. //
  423. #define LINE_LENGTH 80
  424. typedef char TextLine[LINE_LENGTH + 1];
  425. typedef FormatType FormatLine[LINE_LENGTH + 1];
  426. //
  427. // Messages
  428. //
  429. #define MAX_MSG_LINES 5
  430. static TextLine MessageChr[MAX_MSG_LINES];
  431. static FormatLine MessageFmt[MAX_MSG_LINES];
  432. static FormatType CurrentMsgFormat;
  433. static int MsgCursorX = 1;
  434. static int MsgCursorY = 1;
  435. //
  436. // Text
  437. //
  438. #define MAX_TEXT_LINES 25
  439. #define TEXT_LINE_LENGTH 80
  440. static TextLine TextChr[MAX_TEXT_LINES];
  441. static FormatLine TextFmt[MAX_TEXT_LINES];
  442. static FormatType CurrentTextFormat;
  443. static int TextCursorX = 1;
  444. static int TextCursorY = 1;
  445. //
  446. // Generalised text buffer
  447. // Top left corner is x=1, y=1
  448. //
  449. static TextLine *AText;
  450. static FormatLine *Format;
  451. static FormatType CurrentFormat;
  452. static int CursorX = 1;
  453. static int CursorY = 1;
  454. static int MaxLine;
  455. static int TTop;
  456. static int TLeft;
  457. static int TWidth;
  458. static int THeight;
  459. //
  460. // The monster to use for showing mimics. Changes every 10 turns.
  461. //
  462. static MonsterIdType mimicmonst = MIMIC;
  463. /* =============================================================================
  464. * Local functions
  465. */
  466. /* =============================================================================
  467. * FUNCTION: calc_scroll
  468. *
  469. * DESCRIPTION:
  470. * Calculate the new scroll position of the map based on the player's current
  471. * position.
  472. *
  473. * PARAMETERS:
  474. *
  475. * None.
  476. *
  477. * RETURN VALUE:
  478. *
  479. * true if the new scroll position differs from the previous scroll position.
  480. */
  481. static int calc_scroll(void) {
  482. int ox, oy;
  483. ox = MapTileLeft;
  484. oy = MapTileTop;
  485. if (MapTileHeight < MAXY) {
  486. MapTileTop = playery - MapTileHeight / 2;
  487. if (MapTileTop < 0)
  488. MapTileTop = 0;
  489. if ((MapTileTop + MapTileHeight) > MAXY)
  490. MapTileTop = MAXY - MapTileHeight;
  491. } else
  492. MapTileTop = 0;
  493. if (MapTileWidth < MAXX) {
  494. MapTileLeft = playerx - MapTileWidth / 2;
  495. if (MapTileLeft < 0)
  496. MapTileLeft = 0;
  497. if ((MapTileLeft + MapTileWidth) > MAXX)
  498. MapTileLeft = MAXX - MapTileWidth;
  499. } else
  500. MapTileLeft = 0;
  501. //
  502. // return true if the map requires scrolling
  503. //
  504. return (MapTileLeft != ox) || (MapTileTop != oy);
  505. }
  506. /*
  507. * Repaint flag to force redraw of everything, not just deltas
  508. */
  509. static int Repaint = 0;
  510. /* =============================================================================
  511. * FUNCTION: PaintStatus
  512. *
  513. * DESCRIPTION:
  514. * Paint the status area.
  515. *
  516. * PARAMETERS:
  517. *
  518. * DC : The device context for the painting
  519. *
  520. * RETURN VALUE:
  521. *
  522. * None.
  523. */
  524. static void PaintStatus(void) {
  525. char Line[81];
  526. char Buf[81];
  527. int i;
  528. if (Repaint) {
  529. SetAPen(UlarnRP, WHITE_PEN);
  530. SetDrMd(UlarnRP, JAM1);
  531. RectFill(UlarnRP, StatusLeft, StatusTop, StatusLeft + StatusWidth - 1,
  532. StatusTop + StatusHeight - 1);
  533. }
  534. SetDrMd(UlarnRP, JAM2);
  535. SetAPen(UlarnRP, BLACK_PEN);
  536. //
  537. // Build the top status line
  538. //
  539. Line[0] = 0;
  540. /* Spells */
  541. if (c[SPELLMAX] > 99)
  542. sprintf(Buf, "Spells:%3ld(%3ld)", c[SPELLS], c[SPELLMAX]);
  543. else
  544. sprintf(Buf, "Spells:%3ld(%2ld) ", c[SPELLS], c[SPELLMAX]);
  545. strcat(Line, Buf);
  546. /* AC, WC */
  547. sprintf(Buf, " AC: %-3ld WC: %-3ld Level", c[AC], c[WCLASS]);
  548. strcat(Line, Buf);
  549. /* Level */
  550. if (c[LEVEL] > 99)
  551. sprintf(Buf, "%3ld", c[LEVEL]);
  552. else
  553. sprintf(Buf, " %-2ld", c[LEVEL]);
  554. strcat(Line, Buf);
  555. /* Exp, class */
  556. sprintf(Buf, " Exp: %-9ld %s", c[EXPERIENCE], class[c[LEVEL] - 1]);
  557. strcat(Line, Buf);
  558. Move(UlarnRP, StatusLeft, StatusTop + CharBaseline);
  559. Text(UlarnRP, Line, strlen(Line));
  560. //
  561. // Format the second line of the status
  562. //
  563. sprintf(Buf, "%ld (%ld)", c[HP], c[HPMAX]);
  564. sprintf(Line,
  565. "HP: %11s STR=%-2ld INT=%-2ld WIS=%-2ld CON=%-2ld DEX=%-2ld "
  566. "CHA=%-2ld LV:",
  567. Buf, c[STRENGTH] + c[STREXTRA], c[INTELLIGENCE], c[WISDOM],
  568. c[CONSTITUTION], c[DEXTERITY], c[CHARISMA]);
  569. if ((level == 0) || (wizard))
  570. c[TELEFLAG] = 0;
  571. if (c[TELEFLAG])
  572. strcat(Line, " ?");
  573. else
  574. strcat(Line, levelname[level]);
  575. sprintf(Buf, " Gold: %-8ld", c[GOLD]);
  576. strcat(Line, Buf);
  577. Move(UlarnRP, StatusLeft, StatusTop + CharHeight + CharBaseline);
  578. Text(UlarnRP, Line, strlen(Line));
  579. //
  580. // Mark all character values as displayed.
  581. //
  582. c[TMP] = c[STRENGTH] + c[STREXTRA];
  583. for (i = 0; i < 100; i++)
  584. cbak[i] = c[i];
  585. }
  586. /* Effects strings */
  587. static struct bot_side_def {
  588. int typ;
  589. char *string;
  590. } bot_data[] = {{STEALTH, "Stealth "}, {UNDEADPRO, "Undead Pro"},
  591. {SPIRITPRO, "Spirit Pro"}, {CHARMCOUNT, "Charm "},
  592. {TIMESTOP, "Time Stop "}, {HOLDMONST, "Hold Monst"},
  593. {GIANTSTR, "Giant Str "}, {FIRERESISTANCE, "Fire Resit"},
  594. {DEXCOUNT, "Dexterity "}, {STRCOUNT, "Strength "},
  595. {SCAREMONST, "Scare "}, {HASTESELF, "Haste Self"},
  596. {CANCELLATION, "Cancel "}, {INVISIBILITY, "Invisible "},
  597. {ALTPRO, "Protect 3 "}, {PROTECTIONTIME, "Protect 2 "},
  598. {WTW, "Wall-Walk "}};
  599. /* =============================================================================
  600. * FUNCTION: PaintEffects
  601. *
  602. * DESCRIPTION:
  603. * Paint the effects display.
  604. *
  605. * PARAMETERS:
  606. *
  607. * DC : The DC to be painted.
  608. *
  609. * RETURN VALUE:
  610. *
  611. * None.
  612. */
  613. static void PaintEffects(void) {
  614. int i, idx;
  615. int WasSet;
  616. int IsSet;
  617. if (Repaint) {
  618. SetAPen(UlarnRP, WHITE_PEN);
  619. SetDrMd(UlarnRP, JAM1);
  620. RectFill(UlarnRP, EffectsLeft, EffectsTop, EffectsLeft + EffectsWidth - 1,
  621. EffectsTop + EffectsHeight - 1);
  622. }
  623. SetAPen(UlarnRP, BLACK_PEN);
  624. SetDrMd(UlarnRP, JAM2);
  625. for (i = 0; i < 17; i++) {
  626. idx = bot_data[i].typ;
  627. WasSet = (cbak[idx] != 0);
  628. IsSet = (c[idx] != 0);
  629. if ((Repaint) || (IsSet != WasSet)) {
  630. if (IsSet) {
  631. Move(UlarnRP, EffectsLeft, EffectsTop + i * CharHeight + CharBaseline);
  632. Text(UlarnRP, bot_data[i].string, strlen(bot_data[i].string));
  633. } else {
  634. Move(UlarnRP, EffectsLeft, EffectsTop + i * CharHeight + CharBaseline);
  635. Text(UlarnRP, " ", 10);
  636. }
  637. }
  638. cbak[idx] = c[idx];
  639. }
  640. }
  641. /* =============================================================================
  642. * FUNCTION: GetTile
  643. *
  644. * DESCRIPTION:
  645. * Get the tile to be displayed for a location on the map.
  646. *
  647. * PARAMETERS:
  648. *
  649. * x : The x coordinate for the tile
  650. *
  651. * y : The y coordiante for the tile
  652. *
  653. * TileId : This is set to the tile to be displayed for (x, y).
  654. *
  655. * RETURN VALUE:
  656. *
  657. * None.
  658. */
  659. static void GetTile(int x, int y, int *TileId) {
  660. MonsterIdType k;
  661. if ((x == playerx) && (y == playery) && (c[BLINDCOUNT] == 0)) {
  662. //
  663. // This is the square containing the player and the players isn't
  664. // blind, so return the player tile.
  665. //
  666. *TileId = PlayerTiles[class_num][(int)sex];
  667. return;
  668. }
  669. //
  670. // Work out what is here
  671. //
  672. if (know[x][y] == OUNKNOWN) {
  673. //
  674. // The player doesn't know what is at this position.
  675. //
  676. *TileId = objtilelist[OUNKNOWN];
  677. } else {
  678. k = mitem[x][y].mon;
  679. if (k != 0) {
  680. if ((c[BLINDCOUNT] == 0) && (((stealth[x][y] & STEALTH_SEEN) != 0) ||
  681. ((stealth[x][y] & STEALTH_AWAKE) != 0))) {
  682. //
  683. // There is a monster here and the player is not blind and the
  684. // monster is seen or awake.
  685. //
  686. if (k == MIMIC) {
  687. if ((gtime % 10) == 0)
  688. while ((mimicmonst = rnd(MAXMONST)) == INVISIBLESTALKER)
  689. ;
  690. *TileId = monsttilelist[mimicmonst];
  691. } else if ((k == INVISIBLESTALKER) && (c[SEEINVISIBLE] == 0))
  692. *TileId = objtilelist[(int)know[x][y]];
  693. else if ((k >= DEMONLORD) && (k <= LUCIFER) && (c[EYEOFLARN] == 0))
  694. /* demons are invisible if not have the eye */
  695. *TileId = objtilelist[(int)know[x][y]];
  696. else
  697. *TileId = monsttilelist[k];
  698. } /* can see monster */
  699. else
  700. /*
  701. * The monster at this location is not known to the player, so show
  702. * the tile for the item at this location
  703. */
  704. *TileId = objtilelist[(int)know[x][y]];
  705. } /* monster here */
  706. else {
  707. k = know[x][y];
  708. *TileId = objtilelist[k];
  709. }
  710. }
  711. /* Handle walls */
  712. if (*TileId == objtilelist[OWALL])
  713. *TileId = WALL_TILES + iarg[x][y];
  714. }
  715. /* =============================================================================
  716. * FUNCTION: PaintMap
  717. *
  718. * DESCRIPTION:
  719. * Repaint the map.
  720. *
  721. * PARAMETERS:
  722. *
  723. * DC : The device context to be painted.
  724. *
  725. * RETURN VALUE:
  726. *
  727. * None.
  728. */
  729. static void PaintMap(void) {
  730. int x, y;
  731. int sx, sy;
  732. int mx, my;
  733. int TileId;
  734. int TileX;
  735. int TileY;
  736. mx = MapTileLeft + MapTileWidth;
  737. my = MapTileTop + MapTileHeight;
  738. if (my > MAXY)
  739. my = MAXY;
  740. if (mx > MAXX)
  741. mx = MAXX;
  742. sx = 0;
  743. for (x = MapTileLeft; x < mx; x++) {
  744. sy = 0;
  745. for (y = MapTileTop; y < my; y++) {
  746. GetTile(x, y, &TileId);
  747. TileX = (TileId % 16) * TileWidth;
  748. TileY = (TileId / 16) * TileHeight;
  749. BltBitMapRastPort(UlarnGfx, TileX, TileY, UlarnRP,
  750. MapLeft + sx * TileWidth, MapTop + sy * TileHeight,
  751. TileWidth, TileHeight, 0xc0);
  752. sy++;
  753. }
  754. sx++;
  755. }
  756. sx = playerx - MapTileLeft;
  757. sy = playery - MapTileTop;
  758. if ((sx >= 0) && (sx < MapTileWidth) && (sy >= 0) && (sy < MapTileHeight)) {
  759. TileId = TILE_CURSOR1;
  760. TileX = (TileId % 16) * TileWidth;
  761. TileY = (TileId / 16) * TileHeight;
  762. BltBitMapRastPort(UlarnGfx, TileX, TileY, UlarnRP, MapLeft + sx * TileWidth,
  763. MapTop + sy * TileHeight, TileWidth, TileHeight, 0x80);
  764. TileId = TILE_CURSOR2;
  765. TileX = (TileId % 16) * TileWidth;
  766. TileY = (TileId / 16) * TileHeight;
  767. BltBitMapRastPort(UlarnGfx, TileX, TileY, UlarnRP, MapLeft + sx * TileWidth,
  768. MapTop + sy * TileHeight, TileWidth, TileHeight, 0xe0);
  769. }
  770. }
  771. /* =============================================================================
  772. * FUNCTION: PaintTextWindow
  773. *
  774. * DESCRIPTION:
  775. * Repaint the window in text mode.
  776. *
  777. * PARAMETERS:
  778. *
  779. * DC : The device contect to be painted.
  780. *
  781. * RETURN VALUE:
  782. *
  783. * None.
  784. */
  785. static void PaintTextWindow(void) {
  786. int sx, ex, y;
  787. FormatType Fmt;
  788. SetAPen(UlarnRP, WHITE_PEN);
  789. SetDrMd(UlarnRP, JAM1);
  790. RectFill(UlarnRP, TLeft, TTop, TLeft + TWidth - 1, TTop + THeight - 1);
  791. SetDrMd(UlarnRP, JAM2);
  792. for (y = 0; y < MaxLine; y++) {
  793. sx = 0;
  794. while (sx < LINE_LENGTH) {
  795. Fmt = Format[y][sx];
  796. ex = sx;
  797. while ((ex < LINE_LENGTH) && (Format[y][ex] == Fmt))
  798. ex++;
  799. switch (Fmt) {
  800. case FORMAT_NORMAL:
  801. SetAPen(UlarnRP, BLACK_PEN);
  802. break;
  803. case FORMAT_STANDOUT:
  804. SetAPen(UlarnRP, RED_PEN);
  805. break;
  806. case FORMAT_STANDOUT2:
  807. SetAPen(UlarnRP, GREEN_PEN);
  808. break;
  809. case FORMAT_STANDOUT3:
  810. SetAPen(UlarnRP, BLUE_PEN);
  811. break;
  812. default:
  813. break;
  814. }
  815. Move(UlarnRP, TLeft + sx * CharWidth,
  816. TTop + y * CharHeight + CharBaseline);
  817. Text(UlarnRP, AText[y] + sx, ex - sx);
  818. sx = ex;
  819. }
  820. }
  821. }
  822. /* =============================================================================
  823. * FUNCTION: PaintMapWindow
  824. *
  825. * DESCRIPTION:
  826. * Repaint the window in map mode
  827. *
  828. * PARAMETERS:
  829. *
  830. * DC : The device context to be painted.
  831. *
  832. * RETURN VALUE:
  833. *
  834. * None.
  835. */
  836. static void PaintMapWindow(void) {
  837. int RectLeft;
  838. int RectTop;
  839. int RectRight;
  840. int RectBottom;
  841. //
  842. // Message area
  843. //
  844. RectLeft = MessageLeft;
  845. RectTop = MessageTop - SEPARATOR_HEIGHT;
  846. RectRight = MessageLeft + MessageWidth;
  847. RectBottom = RectTop + 2;
  848. SetAPen(UlarnRP, LIGHT_PEN);
  849. RectFill(UlarnRP, RectLeft, RectTop, RectRight - 1, RectBottom - 1);
  850. RectTop = RectBottom;
  851. RectBottom = RectTop + 4;
  852. SetAPen(UlarnRP, MID_PEN);
  853. RectFill(UlarnRP, RectLeft, RectTop, RectRight - 1, RectBottom - 1);
  854. RectTop = RectBottom;
  855. RectBottom = RectTop + 2;
  856. SetAPen(UlarnRP, DARK_PEN);
  857. RectFill(UlarnRP, RectLeft, RectTop, RectRight - 1, RectBottom - 1);
  858. //
  859. // Status area
  860. //
  861. RectLeft = StatusLeft;
  862. RectTop = StatusTop - SEPARATOR_HEIGHT;
  863. RectRight = StatusLeft + StatusWidth;
  864. RectBottom = RectTop + 2;
  865. SetAPen(UlarnRP, LIGHT_PEN);
  866. RectFill(UlarnRP, RectLeft, RectTop, RectRight - 1, RectBottom - 1);
  867. RectTop = RectBottom;
  868. RectBottom = RectTop + 4;
  869. SetAPen(UlarnRP, MID_PEN);
  870. RectFill(UlarnRP, RectLeft, RectTop, RectRight - 1, RectBottom - 1);
  871. RectTop = RectBottom;
  872. RectBottom = RectTop + 2;
  873. SetAPen(UlarnRP, DARK_PEN);
  874. RectFill(UlarnRP, RectLeft, RectTop, RectRight - 1, RectBottom - 1);
  875. //
  876. // Effects area
  877. //
  878. RectLeft = EffectsLeft - SEPARATOR_WIDTH;
  879. RectTop = EffectsTop;
  880. RectRight = RectLeft + 2;
  881. RectBottom = EffectsTop + EffectsHeight;
  882. SetAPen(UlarnRP, LIGHT_PEN);
  883. RectFill(UlarnRP, RectLeft, RectTop, RectRight - 1, RectBottom - 1);
  884. RectLeft = RectRight;
  885. RectRight = RectLeft + 4;
  886. RectBottom = EffectsTop + EffectsHeight + 2;
  887. SetAPen(UlarnRP, MID_PEN);
  888. RectFill(UlarnRP, RectLeft, RectTop, RectRight - 1, RectBottom - 1);
  889. RectLeft = RectRight;
  890. RectRight = RectLeft + 2;
  891. RectBottom = EffectsTop + EffectsHeight;
  892. SetAPen(UlarnRP, DARK_PEN);
  893. RectFill(UlarnRP, RectLeft, RectTop, RectRight - 1, RectBottom - 1);
  894. PaintStatus();
  895. PaintEffects();
  896. PaintMap();
  897. PaintTextWindow();
  898. }
  899. /* =============================================================================
  900. * FUNCTION: PaintWindow
  901. *
  902. * DESCRIPTION:
  903. * Repaint the window.
  904. *
  905. * PARAMETERS:
  906. *
  907. * DC : The device context to be painted
  908. *
  909. * RETURN VALUE:
  910. *
  911. * None.
  912. */
  913. static void PaintWindow(void) {
  914. Repaint = 1;
  915. SetAPen(UlarnRP, WHITE_PEN);
  916. RectFill(UlarnRP, 0, 0, UlarnScreen->Width - 1, UlarnScreen->Height - 1);
  917. SetBPen(UlarnRP, WHITE_PEN);
  918. SetDrMd(UlarnRP, JAM2);
  919. if (CurrentDisplayMode == DISPLAY_MAP)
  920. PaintMapWindow();
  921. else
  922. PaintTextWindow();
  923. Repaint = 0;
  924. }
  925. /* =============================================================================
  926. * FUNCTION: Resize
  927. *
  928. * DESCRIPTION:
  929. * This procedure handles resizing the window in response to any event that
  930. * requires the sub-window size and position to be recalculated.
  931. *
  932. * PARAMETERS:
  933. *
  934. * hwnd : The handle of the window being resized
  935. *
  936. * RETURN VALUE:
  937. *
  938. * None.
  939. */
  940. static void Resize(void) {
  941. int ClientWidth = 0;
  942. int ClientHeight = 0;
  943. ClientWidth = UlarnScreen->Width;
  944. ClientHeight = UlarnScreen->Height;
  945. //
  946. // Calculate the message window size and position
  947. //
  948. MessageWidth = ClientWidth;
  949. MessageHeight = CharHeight * MAX_MSG_LINES + 2;
  950. MessageLeft = 0;
  951. MessageTop = ClientHeight - MessageHeight - 1;
  952. //
  953. // Calculate the Status window size and position
  954. //
  955. StatusLeft = 0;
  956. StatusHeight = CharHeight * 2 + 2;
  957. StatusTop = (MessageTop - SEPARATOR_HEIGHT) - StatusHeight;
  958. StatusWidth = ClientWidth;
  959. //
  960. // Calculate the Effects window size and position
  961. //
  962. EffectsLeft = ClientWidth - CharWidth * 10;
  963. EffectsTop = 0;
  964. EffectsWidth = CharWidth * 10;
  965. EffectsHeight = StatusTop - SEPARATOR_HEIGHT;
  966. //
  967. // Calculate the size and position of the map window
  968. //
  969. MapLeft = 0;
  970. MapTop = UlarnScreen->BarHeight;
  971. MapWidth = EffectsLeft - SEPARATOR_WIDTH;
  972. MapHeight = (StatusTop - SEPARATOR_HEIGHT) - MapTop;
  973. MapTileWidth = MapWidth / TileWidth;
  974. MapTileHeight = MapHeight / TileHeight;
  975. //
  976. // Calculate the size and position of the text window
  977. //
  978. TextWidth = CharWidth * LINE_LENGTH;
  979. TextHeight = CharHeight * MAX_TEXT_LINES;
  980. TextLeft = (ClientWidth - TextWidth) / 2;
  981. TextTop = (ClientHeight - TextHeight) / 2;
  982. //
  983. // Check if should draw a border around the text page when it is displayed
  984. //
  985. ShowTextBorder = (TextLeft >= BORDER_SIZE) && (TextTop >= BORDER_SIZE);
  986. //
  987. // If the map window is bigger than required to display the map, then centre
  988. // the map in the window.
  989. //
  990. if (MapTileWidth > MAXX) {
  991. MapTileWidth = MAXX;
  992. MapLeft = (MapWidth - MapTileWidth * TileWidth) / 2;
  993. }
  994. if (MapTileHeight > MAXY) {
  995. MapTileHeight = MAXY;
  996. MapTop = (MapHeight - MapTileHeight * TileHeight) / 2;
  997. }
  998. if (CurrentDisplayMode == DISPLAY_MAP) {
  999. TLeft = MessageLeft;
  1000. TTop = MessageTop;
  1001. TWidth = MessageWidth;
  1002. THeight = MessageHeight;
  1003. } else {
  1004. TLeft = TextLeft;
  1005. TTop = TextTop;
  1006. TWidth = TextWidth;
  1007. THeight = TextHeight;
  1008. }
  1009. //
  1010. // calculate the map scroll position for the current player position
  1011. //
  1012. calc_scroll();
  1013. //
  1014. // Force the window to redraw
  1015. //
  1016. PaintWindow();
  1017. //
  1018. // Show the cursor if required
  1019. //
  1020. if (CaretActive) {
  1021. SetAPen(UlarnRP, BLUE_PEN);
  1022. RectFill(UlarnRP, TLeft + (CursorX - 1) * CharWidth,
  1023. TTop + (CursorY - 1) * CharHeight + 2,
  1024. TLeft + (CursorX)*CharWidth - 1,
  1025. TTop + (CursorY)*CharHeight + 2 - 1);
  1026. }
  1027. }
  1028. /* =============================================================================
  1029. * FUNCTION: HandleInput
  1030. *
  1031. * DESCRIPTION:
  1032. * This procedure handles the next IntuiMessage and performs input
  1033. * processing for the event that was received.
  1034. * The Event variable is set to the event corresponding to the input
  1035. * received.
  1036. *
  1037. * PARAMETERS:
  1038. *
  1039. * None.
  1040. *
  1041. * RETURN VALUE:
  1042. *
  1043. * None.
  1044. */
  1045. static void HandleInput(void) {
  1046. struct IntuiMessage *Msg;
  1047. WaitPort(UlarnWindow->UserPort);
  1048. Msg = (struct IntuiMessage *)GetMsg(UlarnWindow->UserPort);
  1049. switch (Msg->Class) {
  1050. case IDCMP_MENUPICK:
  1051. /* A menu item has been selected. */
  1052. DoMenuSelection(Msg->Code);
  1053. break;
  1054. case IDCMP_VANILLAKEY: {
  1055. /* An ASCII keypress */
  1056. ActionType Action;
  1057. int Found = 0;
  1058. int i;
  1059. int ModKey = M_ASCII;
  1060. if ((Msg->Qualifier & IEQUALIFIER_NUMERICPAD) != 0) {
  1061. ModKey = M_NUMPAD;
  1062. if (((Msg->Qualifier & IEQUALIFIER_LSHIFT) != 0) ||
  1063. ((Msg->Qualifier & IEQUALIFIER_RSHIFT) != 0))
  1064. ModKey |= M_SHIFT;
  1065. if ((Msg->Qualifier & IEQUALIFIER_CONTROL) != 0)
  1066. ModKey |= M_CTRL;
  1067. }
  1068. Action = ACTION_NULL;
  1069. while ((Action < ACTION_COUNT) && (!Found)) {
  1070. for (i = 0; i < MAX_KEY_BINDINGS; i++) {
  1071. if ((Msg->Code == KeyMap[Action][i].VirtKey) &&
  1072. (KeyMap[Action][i].ModKey == ModKey))
  1073. Found = 1;
  1074. }
  1075. if (!Found)
  1076. Action++;
  1077. }
  1078. if (Found)
  1079. Event = Action;
  1080. else {
  1081. /* Check run key */
  1082. if ((Msg->Code == RunKeyMap.VirtKey) && (RunKeyMap.ModKey == ModKey))
  1083. Runkey = 1;
  1084. }
  1085. EventChar = (char)Msg->Code;
  1086. GotChar = 1;
  1087. break;
  1088. }
  1089. case IDCMP_RAWKEY: {
  1090. /* A keypress that does not translate to a single ASCII character */
  1091. ActionType Action;
  1092. int ModKey = 0;
  1093. int Found = 0;
  1094. int i;
  1095. if (((Msg->Qualifier & IEQUALIFIER_LSHIFT) != 0) ||
  1096. ((Msg->Qualifier & IEQUALIFIER_RSHIFT) != 0))
  1097. ModKey |= M_SHIFT;
  1098. if ((Msg->Qualifier & IEQUALIFIER_CONTROL) != 0)
  1099. ModKey |= M_CTRL;
  1100. Action = ACTION_NULL;
  1101. while ((Action < ACTION_COUNT) && (!Found)) {
  1102. for (i = 0; i < MAX_KEY_BINDINGS; i++) {
  1103. if ((Msg->Code == KeyMap[Action][i].VirtKey) &&
  1104. (KeyMap[Action][i].ModKey == ModKey))
  1105. Found = 1;
  1106. }
  1107. if (!Found)
  1108. Action++;
  1109. }
  1110. if (Found)
  1111. Event = Action;
  1112. else {
  1113. /* Check run key */
  1114. if ((Msg->Code == RunKeyMap.VirtKey) && (RunKeyMap.ModKey == ModKey))
  1115. Runkey = 1;
  1116. }
  1117. break;
  1118. }
  1119. }
  1120. ReplyMsg((struct Message *)Msg);
  1121. }
  1122. /* =============================================================================
  1123. * Exported functions
  1124. */
  1125. /* =============================================================================
  1126. * FUNCTION: init_app
  1127. */
  1128. int init_app(void) {
  1129. int x, y;
  1130. struct ScreenModeRequester *req = NULL;
  1131. long ScreenMode;
  1132. //
  1133. // Open the Amiga libraries required
  1134. //
  1135. IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 0L);
  1136. GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0L);
  1137. AslBase = OpenLibrary("asl.library", 36L);
  1138. if (AslBase == NULL) {
  1139. printf("Error: ULarn requires the ASL Library\n");
  1140. return 0;
  1141. }
  1142. //
  1143. // Ask for the screen mode
  1144. //
  1145. req = AllocAslRequestTags(ASL_ScreenModeRequest, TAG_DONE);
  1146. if (req == NULL) {
  1147. printf("Error: Couldn't allocate the screen mode requester\n");
  1148. return 0;
  1149. }
  1150. if (AslRequestTags(req, TAG_DONE))
  1151. ScreenMode = req->sm_DisplayID;
  1152. FreeAslRequest(req);
  1153. //
  1154. // Create the screen
  1155. //
  1156. if (ModeNotAvailable(ScreenMode)) {
  1157. printf("Error: Requested screen mode 0x%X is not available\n", ScreenMode);
  1158. return 0;
  1159. }
  1160. //
  1161. // Open the font and get the font metrics
  1162. //
  1163. UlarnFont = OpenDiskFont(&UlarnTextAttr);
  1164. if (UlarnFont == NULL) {
  1165. printf("Error: Couldn't open font\n");
  1166. return 0;
  1167. }
  1168. CharWidth = UlarnFont->tf_XSize;
  1169. CharHeight = UlarnFont->tf_YSize;
  1170. CharBaseline = UlarnFont->tf_Baseline + 2;
  1171. UlarnScreen =
  1172. OpenScreenTags(NULL, SA_Pens, UlarnPens, SA_DisplayID, ScreenMode,
  1173. SA_Width, STDSCREENWIDTH, SA_Height, STDSCREENHEIGHT,
  1174. SA_Depth, 8, SA_Title, "Ularn", SA_Type, CUSTOMSCREEN,
  1175. SA_ShowTitle, TRUE, SA_Font, &UlarnTextAttr, TAG_DONE);
  1176. if (UlarnScreen == NULL) {
  1177. printf("Error: Couldn't open Ularn screen\n");
  1178. return 0;
  1179. }
  1180. //
  1181. // Create the window
  1182. //
  1183. UlarnWindow = OpenWindowTags(
  1184. NULL, WA_Left, 0, WA_Top, 0, WA_Width, UlarnScreen->Width, WA_Height,
  1185. UlarnScreen->Height, WA_IDCMP,
  1186. IDCMP_VANILLAKEY | IDCMP_RAWKEY | IDCMP_MENUPICK, WA_Title, "Ularn",
  1187. WA_CustomScreen, UlarnScreen, WA_DetailPen, WHITE_PEN, WA_BlockPen,
  1188. MID_PEN, WA_Borderless, TRUE, WA_Backdrop, TRUE, WA_Activate, TRUE,
  1189. WA_SmartRefresh, TRUE, TAG_DONE);
  1190. if (UlarnWindow == NULL) {
  1191. printf("Error: Couldn't create Ularn window\n");
  1192. return 0;
  1193. }
  1194. if (!MakeMenuStructure(UlarnWindow, UlarnMenu)) {
  1195. printf("Error: Couldn't make menu\n");
  1196. return 0;
  1197. }
  1198. UlarnRP = UlarnWindow->RPort;
  1199. //
  1200. // Load the graphics
  1201. //
  1202. UlarnGfx = ReadIff(TileBMName, UlarnPalette);
  1203. if (UlarnGfx == NULL) {
  1204. printf("Error: Could't open graphics tiles");
  1205. return 0;
  1206. }
  1207. //
  1208. // Setup the palette
  1209. //
  1210. for (x = 0; x < 256; x++) {
  1211. SetRGB32(&(UlarnScreen->ViewPort), x, (UlarnPalette[x] & 0xff0000) << 8,
  1212. (UlarnPalette[x] & 0x00ff00) << 16,
  1213. (UlarnPalette[x] & 0x0000ff) << 24);
  1214. }
  1215. //
  1216. // Clear the text buffers
  1217. //
  1218. for (y = 0; y < MAX_MSG_LINES; y++) {
  1219. for (x = 0; x < LINE_LENGTH; x++) {
  1220. MessageChr[y][x] = ' ';
  1221. MessageFmt[y][x] = FORMAT_NORMAL;
  1222. }
  1223. MessageChr[y][LINE_LENGTH] = 0;
  1224. }
  1225. for (y = 0; y < MAX_TEXT_LINES; y++) {
  1226. for (x = 0; x < LINE_LENGTH; x++) {
  1227. TextChr[y][x] = ' ';
  1228. TextFmt[y][x] = FORMAT_NORMAL;
  1229. }
  1230. TextChr[y][LINE_LENGTH] = 0;
  1231. }
  1232. //
  1233. // Set the initial text buffers
  1234. //
  1235. CursorX = MsgCursorX;
  1236. CursorY = MsgCursorY;
  1237. CurrentFormat = CurrentMsgFormat;
  1238. AText = MessageChr;
  1239. Format = MessageFmt;
  1240. MaxLine = MAX_MSG_LINES;
  1241. TLeft = MessageLeft;
  1242. TTop = MessageTop;
  1243. TWidth = MessageWidth;
  1244. THeight = MessageHeight;
  1245. //
  1246. // Call resize to perform initial sizing and trigger the intial redraw
  1247. //
  1248. Resize();
  1249. return 1;
  1250. }
  1251. /* =============================================================================
  1252. * FUNCTION: close_app
  1253. */
  1254. void close_app(void) {
  1255. if (UlarnGfx != NULL) {
  1256. FreeBitmap(UlarnGfx);
  1257. UlarnGfx = NULL;
  1258. }
  1259. if (UlarnWindow != NULL) {
  1260. MenuQuit();
  1261. CloseWindow(UlarnWindow);
  1262. UlarnWindow = NULL;
  1263. }
  1264. if (UlarnScreen != NULL) {
  1265. CloseScreen(UlarnScreen);
  1266. UlarnScreen = NULL;
  1267. }
  1268. if (UlarnFont != NULL) {
  1269. CloseFont(UlarnFont);
  1270. UlarnFont = NULL;
  1271. }
  1272. if (AslBase != NULL) {
  1273. CloseLibrary(AslBase);
  1274. AslBase = NULL;
  1275. }
  1276. if (GfxBase != NULL) {
  1277. CloseLibrary((struct Library *)GfxBase);
  1278. GfxBase = NULL;
  1279. }
  1280. if (IntuitionBase != NULL) {
  1281. CloseLibrary((struct Library *)IntuitionBase);
  1282. IntuitionBase = NULL;
  1283. }
  1284. }
  1285. /* =============================================================================
  1286. * FUNCTION: get_normal_input
  1287. */
  1288. ActionType get_normal_input(void) {
  1289. int idx;
  1290. int got_dir;
  1291. Event = ACTION_NULL;
  1292. Runkey = 0;
  1293. /* Process input events until an action has been selected */
  1294. while (Event == ACTION_NULL) {
  1295. HandleInput();
  1296. if (!enhance_interface) {
  1297. if ((Event == ACTION_OPEN_DOOR) || (Event == ACTION_OPEN_CHEST))
  1298. Event = ACTION_NULL;
  1299. }
  1300. }
  1301. /* Check for the run key, and adjust events accordingly */
  1302. if (Runkey) {
  1303. idx = 0;
  1304. got_dir = 0;
  1305. while ((idx < NUM_DIRS) && (!got_dir)) {
  1306. if (DirActions[idx] == Event)
  1307. got_dir = 1;
  1308. else
  1309. idx++;
  1310. }
  1311. if (got_dir)
  1312. /* modify into a run event */
  1313. Event = Event + 1;
  1314. }
  1315. return Event;
  1316. }
  1317. /* =============================================================================
  1318. * FUNCTION: get_prompt_input
  1319. */
  1320. char get_prompt_input(char *prompt, char *answers, int ShowCursor) {
  1321. char *ch;
  1322. Print(prompt);
  1323. //
  1324. // Show the cursor if required
  1325. //
  1326. if (ShowCursor) {
  1327. SetAPen(UlarnRP, BLUE_PEN);
  1328. RectFill(UlarnRP, TLeft + (CursorX - 1) * CharWidth,
  1329. TTop + (CursorY - 1) * CharHeight + 2,
  1330. TLeft + (CursorX)*CharWidth - 1,
  1331. TTop + (CursorY)*CharHeight + 2 - 1);
  1332. CaretActive = 1;
  1333. }
  1334. GotChar = 0;
  1335. while (!GotChar) {
  1336. HandleInput();
  1337. if (GotChar) {
  1338. ch = strchr(answers, EventChar);
  1339. if (ch == NULL) {
  1340. //
  1341. // Not an answer we want
  1342. //
  1343. GotChar = 0;
  1344. }
  1345. }
  1346. }
  1347. if (ShowCursor) {
  1348. SetAPen(UlarnRP, WHITE_PEN);
  1349. RectFill(UlarnRP, TLeft + (CursorX - 1) * CharWidth,
  1350. TTop + (CursorY - 1) * CharHeight + 2,
  1351. TLeft + (CursorX)*CharWidth - 1,
  1352. TTop + (CursorY)*CharHeight + 2 - 1);
  1353. CaretActive = 0;
  1354. }
  1355. return EventChar;
  1356. }
  1357. /* =============================================================================
  1358. * FUNCTION: get_password_input
  1359. */
  1360. void get_password_input(char *password, int Len) {
  1361. char ch;
  1362. char inputchars[256];
  1363. int Pos;
  1364. int value;
  1365. /* get the printable characters on this system */
  1366. Pos = 0;
  1367. for (value = 0; value < 256; value++) {
  1368. if (isprint(value)) {
  1369. inputchars[Pos] = (char)value;
  1370. Pos++;
  1371. }
  1372. }
  1373. /* add CR, BS and null terminator */
  1374. inputchars[Pos++] = '\010';
  1375. inputchars[Pos++] = '\015';
  1376. inputchars[Pos] = '\0';
  1377. Pos = 0;
  1378. do {
  1379. ch = get_prompt_input("", inputchars, 1);
  1380. if (isprint(ch) && (Pos < Len)) {
  1381. password[Pos] = ch;
  1382. Pos++;
  1383. Printc('*');
  1384. } else if (ch == '\010') {
  1385. //
  1386. // Backspace
  1387. //
  1388. if (Pos > 0) {
  1389. CursorX--;
  1390. Printc(' ');
  1391. CursorX--;
  1392. Pos--;
  1393. }
  1394. }
  1395. } while (ch != '\015');
  1396. password[Pos] = 0;
  1397. }
  1398. #if 0
  1399. /* =============================================================================
  1400. * FUNCTION: get_string_input
  1401. */
  1402. static void get_string_input(char *string, int Len)
  1403. {
  1404. char ch;
  1405. char inputchars[256];
  1406. int Pos;
  1407. int value;
  1408. /* get the printable characters on this system */
  1409. Pos = 0;
  1410. for (value = 0; value < 256; value++) {
  1411. if (isprint(value)) {
  1412. inputchars[Pos] = (char)value;
  1413. Pos++;
  1414. }
  1415. }
  1416. /* add CR, BS and null terminator */
  1417. inputchars[Pos++] = '\010';
  1418. inputchars[Pos++] = '\015';
  1419. inputchars[Pos] = '\0';
  1420. Pos = 0;
  1421. do{
  1422. ch = get_prompt_input("", inputchars, 1);
  1423. if (isprint((int)ch) && (Pos < Len)) {
  1424. string[Pos] = ch;
  1425. Pos++;
  1426. Printc(ch);
  1427. }else if (ch == '\010') {
  1428. //
  1429. // Backspace
  1430. //
  1431. if (Pos > 0) {
  1432. CursorX--;
  1433. Printc(' ');
  1434. CursorX--;
  1435. Pos--;
  1436. }
  1437. }
  1438. } while (ch != '\015');
  1439. string[Pos] = 0;
  1440. }
  1441. #endif
  1442. /* =============================================================================
  1443. * FUNCTION: get_num_input
  1444. */
  1445. int get_num_input(int defval) {
  1446. char ch;
  1447. int Pos = 0;
  1448. int value = 0;
  1449. int neg = 0;
  1450. do {
  1451. ch = get_prompt_input("", "-*0123456789\010\015", 1);
  1452. if ((ch == '-') && (Pos == 0)) {
  1453. //
  1454. // Minus
  1455. //
  1456. neg = 1;
  1457. Printc(ch);
  1458. Pos++;
  1459. }
  1460. if (ch == '*')
  1461. return defval;
  1462. else if (ch == '\010') {
  1463. //
  1464. // Backspace
  1465. //
  1466. if (Pos > 0) {
  1467. if ((Pos == 1) && neg)
  1468. neg = 0;
  1469. else
  1470. value = value / 10;
  1471. CursorX--;
  1472. Printc(' ');
  1473. CursorX--;
  1474. Pos--;
  1475. }
  1476. } else if ((ch >= '0') && (ch <= '9')) {
  1477. //
  1478. // digit
  1479. //
  1480. value = value * 10 + (ch - '0');
  1481. Printc(ch);
  1482. Pos++;
  1483. }
  1484. } while (ch != '\015');
  1485. if (Pos == 0)
  1486. return defval;
  1487. else {
  1488. if (neg)
  1489. value = -value;
  1490. return value;
  1491. }
  1492. }
  1493. /* =============================================================================
  1494. * FUNCTION: get_dir_input
  1495. */
  1496. ActionType get_dir_input(char *prompt, int ShowCursor) {
  1497. int got_dir;
  1498. int idx;
  1499. //
  1500. // Display the prompt at the current position
  1501. //
  1502. Print(prompt);
  1503. if (ShowCursor) {
  1504. SetAPen(UlarnRP, BLUE_PEN);
  1505. RectFill(UlarnRP, TLeft + (CursorX - 1) * CharWidth,
  1506. TTop + (CursorY - 1) * CharHeight + 2,
  1507. TLeft + (CursorX)*CharWidth - 1,
  1508. TTop + (CursorY)*CharHeight + 2 - 1);
  1509. CaretActive = 1;
  1510. }
  1511. Event = ACTION_NULL;
  1512. got_dir = 0;
  1513. while (!got_dir) {
  1514. HandleInput();
  1515. idx = 0;
  1516. while ((idx < NUM_DIRS) && (!got_dir)) {
  1517. if (DirActions[idx] == Event)
  1518. got_dir = 1;
  1519. else
  1520. idx++;
  1521. }
  1522. }
  1523. if (ShowCursor) {
  1524. SetAPen(UlarnRP, WHITE_PEN);
  1525. RectFill(UlarnRP, TLeft + (CursorX - 1) * CharWidth,
  1526. TTop + (CursorY - 1) * CharHeight + 2,
  1527. TLeft + (CursorX)*CharWidth - 1,
  1528. TTop + (CursorY)*CharHeight + 2 - 1);
  1529. CaretActive = 0;
  1530. }
  1531. return Event;
  1532. }
  1533. /* =============================================================================
  1534. * FUNCTION: UpdateStatus
  1535. */
  1536. void UpdateStatus(void) {
  1537. if (CurrentDisplayMode == DISPLAY_TEXT)
  1538. /* Don't redisplay if in text mode */
  1539. return;
  1540. PaintStatus();
  1541. }
  1542. /* =============================================================================
  1543. * FUNCTION: UpdateEffects
  1544. */
  1545. void UpdateEffects(void) {
  1546. if (CurrentDisplayMode == DISPLAY_TEXT)
  1547. /* Don't redisplay if in text mode */
  1548. return;
  1549. PaintEffects();
  1550. }
  1551. /* =============================================================================
  1552. * FUNCTION: UpdateStatusAndEffects
  1553. */
  1554. void UpdateStatusAndEffects(void) {
  1555. if (CurrentDisplayMode == DISPLAY_TEXT)
  1556. /* Don't redisplay if in text mode */
  1557. return;
  1558. //
  1559. // Do effects first as update status will mark all effects as current
  1560. //
  1561. PaintEffects();
  1562. PaintStatus();
  1563. }
  1564. /* =============================================================================
  1565. * FUNCTION: set_display
  1566. */
  1567. void set_display(DisplayModeType Mode) {
  1568. //
  1569. // Save the current settings
  1570. //
  1571. if (CurrentDisplayMode == DISPLAY_MAP) {
  1572. MsgCursorX = CursorX;
  1573. MsgCursorY = CursorY;
  1574. CurrentMsgFormat = CurrentFormat;
  1575. } else if (CurrentDisplayMode == DISPLAY_TEXT) {
  1576. TextCursorX = CursorX;
  1577. TextCursorY = CursorY;
  1578. CurrentTextFormat = CurrentFormat;
  1579. }
  1580. CurrentDisplayMode = Mode;
  1581. //
  1582. // Set the text buffer settings for the new display mode
  1583. //
  1584. if (CurrentDisplayMode == DISPLAY_MAP) {
  1585. CursorX = MsgCursorX;
  1586. CursorY = MsgCursorY;
  1587. CurrentFormat = CurrentMsgFormat;
  1588. AText = MessageChr;
  1589. Format = MessageFmt;
  1590. MaxLine = MAX_MSG_LINES;
  1591. TLeft = MessageLeft;
  1592. TTop = MessageTop;
  1593. TWidth = MessageWidth;
  1594. THeight = MessageHeight;
  1595. } else if (CurrentDisplayMode == DISPLAY_TEXT) {
  1596. CursorX = TextCursorX;
  1597. CursorY = TextCursorY;
  1598. CurrentFormat = CurrentTextFormat;
  1599. AText = TextChr;
  1600. Format = TextFmt;
  1601. MaxLine = MAX_TEXT_LINES;
  1602. TLeft = TextLeft;
  1603. TTop = TextTop;
  1604. TWidth = TextWidth;
  1605. THeight = TextHeight;
  1606. }
  1607. PaintWindow();
  1608. }
  1609. /* =============================================================================
  1610. * FUNCTION: IncCursorY
  1611. *
  1612. * DESCRIPTION:
  1613. * Increae the cursor y position, scrolling the text window if requried.
  1614. *
  1615. * PARAMETERS:
  1616. *
  1617. * Count : The number of lines to increase the cursor y position
  1618. *
  1619. * RETURN VALUE:
  1620. *
  1621. * None.
  1622. */
  1623. static void IncCursorY(int Count) {
  1624. int Scroll;
  1625. int inc;
  1626. int Line;
  1627. int x;
  1628. inc = Count;
  1629. Scroll = 0;
  1630. while (inc > 0) {
  1631. CursorY = CursorY + 1;
  1632. if (CursorY > MaxLine) {
  1633. Scroll = 1;
  1634. for (Line = 0; Line < (MaxLine - 1); Line++) {
  1635. for (x = 0; x < LINE_LENGTH; x++) {
  1636. AText[Line][x] = AText[Line + 1][x];
  1637. Format[Line][x] = Format[Line + 1][x];
  1638. }
  1639. }
  1640. CursorY--;
  1641. for (x = 0; x < LINE_LENGTH; x++) {
  1642. AText[MaxLine - 1][x] = ' ';
  1643. Format[MaxLine - 1][x] = FORMAT_NORMAL;
  1644. }
  1645. }
  1646. inc--;
  1647. }
  1648. if (Scroll)
  1649. PaintTextWindow();
  1650. }
  1651. /* =============================================================================
  1652. * FUNCTION: IncCursorX
  1653. *
  1654. * DESCRIPTION:
  1655. * Increase the cursor x position, handling line wrap.
  1656. *
  1657. * PARAMETERS:
  1658. *
  1659. * Count : The amount to increase the cursor x position.
  1660. *
  1661. * RETURN VALUE:
  1662. *
  1663. * None.
  1664. */
  1665. static void IncCursorX(int Count) {
  1666. CursorX = CursorX + Count;
  1667. if (CursorX > LINE_LENGTH) {
  1668. CursorX = 1;
  1669. IncCursorY(1);
  1670. }
  1671. }
  1672. /* =============================================================================
  1673. * FUNCTION: ClearText
  1674. */
  1675. void ClearText(void) {
  1676. int x, y;
  1677. //
  1678. // Clear the text buffer
  1679. //
  1680. for (y = 0; y < MaxLine; y++) {
  1681. for (x = 0; x < LINE_LENGTH; x++) {
  1682. AText[y][x] = ' ';
  1683. Format[y][x] = FORMAT_NORMAL;
  1684. }
  1685. AText[y][LINE_LENGTH] = 0;
  1686. }
  1687. CursorX = 1;
  1688. CursorY = 1;
  1689. //
  1690. // Clear the text area
  1691. //
  1692. PaintTextWindow();
  1693. }
  1694. /* =============================================================================
  1695. * FUNCTION: UlarnBeep
  1696. */
  1697. void UlarnBeep(void) {
  1698. if (!nobeep) {
  1699. //
  1700. //
  1701. //
  1702. DisplayBeep(UlarnScreen);
  1703. }
  1704. }
  1705. /* =============================================================================
  1706. * FUNCTION: MoveCursor
  1707. */
  1708. void MoveCursor(int x, int y) {
  1709. CursorX = x;
  1710. CursorY = y;
  1711. if (CursorX < 1)
  1712. CursorX = 1;
  1713. if (CursorY < 1)
  1714. CursorY = 1;
  1715. if (CursorX > LINE_LENGTH)
  1716. CursorX = LINE_LENGTH;
  1717. if (CursorY > MaxLine)
  1718. CursorY = MaxLine;
  1719. }
  1720. /* =============================================================================
  1721. * FUNCTION: Printc
  1722. */
  1723. void Printc(char c) {
  1724. int incx;
  1725. switch (c) {
  1726. case '\t':
  1727. incx = ((((CursorX - 1) / 8) + 1) * 8 + 1) - CursorX;
  1728. IncCursorX(incx);
  1729. break;
  1730. case '\n':
  1731. CursorX = 1;
  1732. IncCursorY(1);
  1733. break;
  1734. case 13:
  1735. /* Ignore LF */
  1736. break;
  1737. default:
  1738. AText[CursorY - 1][CursorX - 1] = c;
  1739. Format[CursorY - 1][CursorX - 1] = CurrentFormat;
  1740. switch (CurrentFormat) {
  1741. case FORMAT_NORMAL:
  1742. SetAPen(UlarnRP, BLACK_PEN);
  1743. break;
  1744. case FORMAT_STANDOUT:
  1745. SetAPen(UlarnRP, RED_PEN);
  1746. break;
  1747. case FORMAT_STANDOUT2:
  1748. SetAPen(UlarnRP, GREEN_PEN);
  1749. break;
  1750. case FORMAT_STANDOUT3:
  1751. SetAPen(UlarnRP, BLUE_PEN);
  1752. break;
  1753. default:
  1754. break;
  1755. }
  1756. Move(UlarnRP, TLeft + (CursorX - 1) * CharWidth,
  1757. TTop + (CursorY - 1) * CharHeight + CharBaseline);
  1758. Text(UlarnRP, &c, 1);
  1759. IncCursorX(1);
  1760. break;
  1761. }
  1762. }
  1763. /* =============================================================================
  1764. * FUNCTION: Print
  1765. */
  1766. void Print(char *string) {
  1767. int Len;
  1768. int pos;
  1769. if (string == NULL)
  1770. return;
  1771. Len = strlen(string);
  1772. if (Len == 0)
  1773. return;
  1774. for (pos = 0; pos < Len; pos++)
  1775. Printc(string[pos]);
  1776. }
  1777. /* =============================================================================
  1778. * FUNCTION: Printf
  1779. */
  1780. void Printf(char *fmt, ...) {
  1781. char buf[2048];
  1782. va_list argptr;
  1783. va_start(argptr, fmt);
  1784. vsprintf(buf, fmt, argptr);
  1785. va_end(argptr);
  1786. Print(buf);
  1787. }
  1788. /* =============================================================================
  1789. * FUNCTION: Standout
  1790. */
  1791. void Standout(char *String) {
  1792. CurrentFormat = FORMAT_STANDOUT;
  1793. Print(String);
  1794. CurrentFormat = FORMAT_NORMAL;
  1795. }
  1796. /* =============================================================================
  1797. * FUNCTION: SetFormat
  1798. */
  1799. void SetFormat(FormatType format) { CurrentFormat = format; }
  1800. /* =============================================================================
  1801. * FUNCTION: ClearToEOL
  1802. */
  1803. void ClearToEOL(void) {
  1804. int x;
  1805. for (x = CursorX; x <= LINE_LENGTH; x++) {
  1806. AText[CursorY - 1][x - 1] = ' ';
  1807. Format[CursorY - 1][x - 1] = FORMAT_NORMAL;
  1808. }
  1809. Move(UlarnRP, TLeft + (CursorX - 1) * CharWidth,
  1810. TTop + (CursorY - 1) * CharHeight + CharBaseline);
  1811. Text(UlarnRP, &(AText[CursorY - 1][CursorX - 1]),
  1812. (LINE_LENGTH - CursorX) + 1);
  1813. }
  1814. /* =============================================================================
  1815. * FUNCTION: ClearToEOPage
  1816. */
  1817. void ClearToEOPage(int x, int y) {
  1818. int tx, ty;
  1819. for (tx = x; tx <= LINE_LENGTH; tx++) {
  1820. AText[y - 1][tx - 1] = ' ';
  1821. Format[y - 1][tx - 1] = FORMAT_NORMAL;
  1822. }
  1823. Move(UlarnRP, TLeft + (x - 1) * CharWidth,
  1824. TTop + (y - 1) * CharHeight + CharBaseline);
  1825. Text(UlarnRP, &(AText[y - 1][x - 1]), (LINE_LENGTH - x) + 1);
  1826. for (ty = y + 1; ty <= MaxLine; ty++) {
  1827. for (tx = 1; tx <= LINE_LENGTH; tx++) {
  1828. AText[ty - 1][tx - 1] = ' ';
  1829. Format[ty - 1][tx - 1] = FORMAT_NORMAL;
  1830. }
  1831. Move(UlarnRP, TLeft, TTop + (ty - 1) * CharHeight + CharBaseline);
  1832. Text(UlarnRP, AText[ty - 1], LINE_LENGTH);
  1833. }
  1834. }
  1835. /* =============================================================================
  1836. * FUNCTION: show1cell
  1837. */
  1838. void show1cell(int x, int y) {
  1839. int TileId;
  1840. int sx, sy;
  1841. int TileX, TileY;
  1842. /* see nothing if blind */
  1843. if (c[BLINDCOUNT])
  1844. return;
  1845. /* we end up knowing about it */
  1846. know[x][y] = item[x][y];
  1847. if (mitem[x][y].mon != MONST_NONE)
  1848. stealth[x][y] |= STEALTH_SEEN;
  1849. sx = x - MapTileLeft;
  1850. sy = y - MapTileTop;
  1851. if ((sx < 0) || (sx >= MapTileWidth) || (sy < 0) || (sy >= MapTileHeight)) {
  1852. //
  1853. // Tile is not currently in the visible part of the map,
  1854. // so don't draw anything
  1855. //
  1856. return;
  1857. }
  1858. GetTile(x, y, &TileId);
  1859. TileX = (TileId % 16) * TileWidth;
  1860. TileY = (TileId / 16) * TileHeight;
  1861. BltBitMapRastPort(UlarnGfx, TileX, TileY, UlarnRP, MapLeft + sx * TileWidth,
  1862. MapTop + sy * TileHeight, TileWidth, TileHeight, 0xc0);
  1863. }
  1864. /* =============================================================================
  1865. * FUNCTION: showplayer
  1866. */
  1867. void showplayer(void) {
  1868. int sx, sy;
  1869. int TileId;
  1870. int TileX, TileY;
  1871. int scroll;
  1872. //
  1873. // Determine if we need to scroll the map
  1874. //
  1875. scroll = calc_scroll();
  1876. if (scroll)
  1877. PaintMap();
  1878. else {
  1879. sx = playerx - MapTileLeft;
  1880. sy = playery - MapTileTop;
  1881. if ((sx >= 0) && (sx < MapTileWidth) && (sy >= 0) && (sy < MapTileHeight)) {
  1882. if (c[BLINDCOUNT] == 0)
  1883. TileId = PlayerTiles[class_num][(int)sex];
  1884. else
  1885. GetTile(playerx, playery, &TileId);
  1886. TileX = (TileId % 16) * TileWidth;
  1887. TileY = (TileId / 16) * TileHeight;
  1888. BltBitMapRastPort(UlarnGfx, TileX, TileY, UlarnRP,
  1889. MapLeft + sx * TileWidth, MapTop + sy * TileHeight,
  1890. TileWidth, TileHeight, 0xc0);
  1891. TileId = TILE_CURSOR1;
  1892. TileX = (TileId % 16) * TileWidth;
  1893. TileY = (TileId / 16) * TileHeight;
  1894. BltBitMapRastPort(UlarnGfx, TileX, TileY, UlarnRP,
  1895. MapLeft + sx * TileWidth, MapTop + sy * TileHeight,
  1896. TileWidth, TileHeight, 0x80);
  1897. TileId = TILE_CURSOR2;
  1898. TileX = (TileId % 16) * TileWidth;
  1899. TileY = (TileId / 16) * TileHeight;
  1900. BltBitMapRastPort(UlarnGfx, TileX, TileY, UlarnRP,
  1901. MapLeft + sx * TileWidth, MapTop + sy * TileHeight,
  1902. TileWidth, TileHeight, 0xe0);
  1903. } /* If player on visible map area */
  1904. }
  1905. }
  1906. /* =============================================================================
  1907. * FUNCTION: showcell
  1908. */
  1909. void showcell(int x, int y) {
  1910. int minx, maxx;
  1911. int miny, maxy;
  1912. int mx, my;
  1913. int sx, sy;
  1914. int TileX, TileY;
  1915. int TileId;
  1916. int scroll;
  1917. //
  1918. // Determine if we need to scroll the map
  1919. //
  1920. scroll = calc_scroll();
  1921. /*
  1922. * Decide how much the player knows about around him/her.
  1923. */
  1924. if (c[AWARENESS]) {
  1925. minx = x - 3;
  1926. maxx = x + 3;
  1927. miny = y - 3;
  1928. maxy = y + 3;
  1929. } else {
  1930. minx = x - 1;
  1931. maxx = x + 1;
  1932. miny = y - 1;
  1933. maxy = y + 1;
  1934. }
  1935. if (c[BLINDCOUNT]) {
  1936. minx = x;
  1937. maxx = x;
  1938. miny = y;
  1939. maxy = y;
  1940. //
  1941. // Redraw the last player position to remove the cursor
  1942. //
  1943. if (!scroll) {
  1944. //
  1945. // Only redraw if the map is not going to be completely redrawn.
  1946. //
  1947. sx = lastpx - MapTileLeft;
  1948. sy = lastpy - MapTileTop;
  1949. if ((sx >= 0) && (sx < MapTileWidth) && (sy >= 0) &&
  1950. (sy < MapTileHeight)) {
  1951. //
  1952. // Tile is currently visible, so draw it
  1953. //
  1954. GetTile(lastpx, lastpy, &TileId);
  1955. TileX = (TileId % 16) * TileWidth;
  1956. TileY = (TileId / 16) * TileHeight;
  1957. BltBitMapRastPort(UlarnGfx, TileX, TileY, UlarnRP,
  1958. MapLeft + sx * TileWidth, MapTop + sy * TileHeight,
  1959. TileWidth, TileHeight, 0xc0);
  1960. }
  1961. }
  1962. }
  1963. /*
  1964. * Limit the area to the map extents
  1965. */
  1966. if (minx < 0)
  1967. minx = 0;
  1968. if (maxx > MAXX - 1)
  1969. maxx = MAXX - 1;
  1970. if (miny < 0)
  1971. miny = 0;
  1972. if (maxy > MAXY - 1)
  1973. maxy = MAXY - 1;
  1974. for (my = miny; my <= maxy; my++) {
  1975. for (mx = minx; mx <= maxx; mx++) {
  1976. if ((mx == playerx) && (my == playery)) {
  1977. know[mx][my] = item[mx][my];
  1978. if (!scroll) {
  1979. //
  1980. // Only draw if the entire map is not going to be scrolled
  1981. //
  1982. showplayer();
  1983. }
  1984. } else if ((know[mx][my] != item[mx][my]) || /* item changed */
  1985. ((mx == lastpx) && (my == lastpy)) || /* last player pos */
  1986. ((mitem[mx][my].mon != MONST_NONE) && /* unseen monster */
  1987. ((stealth[mx][my] & STEALTH_SEEN) == 0))) {
  1988. //
  1989. // Only draw areas not already known (and hence displayed)
  1990. //
  1991. know[mx][my] = item[mx][my];
  1992. if (mitem[mx][my].mon != MONST_NONE)
  1993. stealth[mx][my] |= STEALTH_SEEN;
  1994. if (!scroll) {
  1995. //
  1996. // Only draw the tile if the map is not going to be scrolled
  1997. //
  1998. sx = mx - MapTileLeft;
  1999. sy = my - MapTileTop;
  2000. if ((sx >= 0) && (sx < MapTileWidth) && (sy >= 0) &&
  2001. (sy < MapTileHeight)) {
  2002. //
  2003. // Tile is currently visible, so draw it
  2004. //
  2005. GetTile(mx, my, &TileId);
  2006. TileX = (TileId % 16) * TileWidth;
  2007. TileY = (TileId / 16) * TileHeight;
  2008. BltBitMapRastPort(
  2009. UlarnGfx, TileX, TileY, UlarnRP, MapLeft + sx * TileWidth,
  2010. MapTop + sy * TileHeight, TileWidth, TileHeight, 0xc0);
  2011. }
  2012. }
  2013. } // if not known
  2014. }
  2015. }
  2016. if (scroll)
  2017. /* scrolling the map window, so repaint everything and return */
  2018. PaintMap();
  2019. }
  2020. /* =============================================================================
  2021. * FUNCTION: drawscreen
  2022. */
  2023. void drawscreen(void) { PaintWindow(); }
  2024. /* =============================================================================
  2025. * FUNCTION: draws
  2026. */
  2027. void draws(int minx, int miny, int maxx, int maxy) { PaintWindow(); }
  2028. /* =============================================================================
  2029. * FUNCTION: mapeffect
  2030. */
  2031. void mapeffect(int x, int y, DirEffectsType effect, int dir) {
  2032. int TileId;
  2033. int sx, sy;
  2034. int TileX, TileY;
  2035. /* see nothing if blind */
  2036. if (c[BLINDCOUNT])
  2037. return;
  2038. sx = x - MapTileLeft;
  2039. sy = y - MapTileTop;
  2040. if ((sx < 0) || (sx >= MapTileWidth) || (sy < 0) || (sy >= MapTileHeight)) {
  2041. //
  2042. // Tile is not currently in the visible part of the map,
  2043. // so don't draw anything
  2044. //
  2045. return;
  2046. }
  2047. TileId = EffectTile[effect][dir];
  2048. TileX = (TileId % 16) * TileWidth;
  2049. TileY = (TileId / 16) * TileHeight;
  2050. BltBitMapRastPort(UlarnGfx, TileX, TileY, UlarnRP, MapLeft + sx * TileWidth,
  2051. MapTop + sy * TileHeight, TileWidth, TileHeight, 0xc0);
  2052. }
  2053. /* =============================================================================
  2054. * FUNCTION: magic_effect_frames
  2055. */
  2056. int magic_effect_frames(MagicEffectsType fx) { return magicfx_tile[fx].Frames; }
  2057. /* =============================================================================
  2058. * FUNCTION: magic_effect
  2059. */
  2060. void magic_effect(int x, int y, MagicEffectsType fx, int frame) {
  2061. int TileId;
  2062. int sx, sy;
  2063. int TileX, TileY;
  2064. if (frame > magicfx_tile[fx].Frames)
  2065. return;
  2066. /*
  2067. * draw the tile that is at this location
  2068. */
  2069. /* see nothing if blind */
  2070. if (c[BLINDCOUNT])
  2071. return;
  2072. sx = x - MapTileLeft;
  2073. sy = y - MapTileTop;
  2074. if ((sx < 0) || (sx >= MapTileWidth) || (sy < 0) || (sy >= MapTileHeight)) {
  2075. //
  2076. // Tile is not currently in the visible part of the map,
  2077. // so don't draw anything
  2078. //
  2079. return;
  2080. }
  2081. if (magicfx_tile[fx].Overlay) {
  2082. GetTile(x, y, &TileId);
  2083. TileX = (TileId % 16) * TileWidth;
  2084. TileY = (TileId / 16) * TileHeight;
  2085. BltBitMapRastPort(UlarnGfx, TileX, TileY, UlarnRP, MapLeft + sx * TileWidth,
  2086. MapTop + sy * TileHeight, TileWidth, TileHeight, 0xc0);
  2087. TileId = magicfx_tile[fx].Tile1[frame];
  2088. TileX = (TileId % 16) * TileWidth;
  2089. TileY = (TileId / 16) * TileHeight;
  2090. BltBitMapRastPort(UlarnGfx, TileX, TileY, UlarnRP, MapLeft + sx * TileWidth,
  2091. MapTop + sy * TileHeight, TileWidth, TileHeight, 0x80);
  2092. TileId = magicfx_tile[fx].Tile2[frame];
  2093. TileX = (TileId % 16) * TileWidth;
  2094. TileY = (TileId / 16) * TileHeight;
  2095. BltBitMapRastPort(UlarnGfx, TileX, TileY, UlarnRP, MapLeft + sx * TileWidth,
  2096. MapTop + sy * TileHeight, TileWidth, TileHeight, 0xe0);
  2097. } else {
  2098. TileId = magicfx_tile[fx].Tile1[frame];
  2099. TileX = (TileId % 16) * TileWidth;
  2100. TileY = (TileId / 16) * TileHeight;
  2101. BltBitMapRastPort(UlarnGfx, TileX, TileY, UlarnRP, MapLeft + sx * TileWidth,
  2102. MapTop + sy * TileHeight, TileWidth, TileHeight, 0xc0);
  2103. }
  2104. }
  2105. /* =============================================================================
  2106. * FUNCTION: nap
  2107. */
  2108. void nap(int delay) {
  2109. //
  2110. // Delay for delay/20 ticks (50 ticks per second)
  2111. //
  2112. Delay(delay / 20);
  2113. }
  2114. //
  2115. //
  2116. //
  2117. static char *UserName;
  2118. /* =============================================================================
  2119. * FUNCTION: GetUser
  2120. */
  2121. void GetUser(char *username, int *uid) {
  2122. FILE *fp;
  2123. char TmpName[80];
  2124. int TmpPid;
  2125. int Found;
  2126. int n;
  2127. /* Set the buffer the name dialog is to use to store the input name */
  2128. UserName = username;
  2129. /* uid = -1 indicated failure to determine uid */
  2130. *uid = -1;
  2131. if (username[0] == 0) {
  2132. //
  2133. // Name is not yet specified, so ask player for the name
  2134. //
  2135. Print("Who are you? ");
  2136. get_string_input(username, USERNAME_LENGTH);
  2137. if (strlen(username) == 0)
  2138. strcpy(username, "Anon");
  2139. }
  2140. /* get the Player Id */
  2141. fp = fopen(PIDName, "rb");
  2142. if (fp == NULL) {
  2143. /* Need to create the PID file. */
  2144. fp = fopen(PIDName, "wb");
  2145. if (fp != NULL) {
  2146. *uid = FIRST_PID;
  2147. fwrite(username, USERNAME_LENGTH + 1, 1, fp);
  2148. fwrite(uid, sizeof(int), 1, fp);
  2149. fclose(fp);
  2150. }
  2151. } else {
  2152. /* search the PID file for this player id */
  2153. Found = 0;
  2154. TmpPid = FIRST_PID;
  2155. while (!feof(fp) && !Found) {
  2156. n = fread(TmpName, USERNAME_LENGTH + 1, 1, fp);
  2157. if (n == 1)
  2158. n = fread(&TmpPid, sizeof(int), 1, fp);
  2159. if (n == 1) {
  2160. if (strcmp(TmpName, username) == 0) {
  2161. *uid = TmpPid;
  2162. Found = 1;
  2163. }
  2164. }
  2165. }
  2166. fclose(fp);
  2167. if (!Found) {
  2168. *uid = TmpPid + 1;
  2169. fp = fopen(PIDName, "ab");
  2170. if (fp != NULL) {
  2171. fwrite(username, USERNAME_LENGTH + 1, 1, fp);
  2172. fwrite(uid, sizeof(int), 1, fp);
  2173. fclose(fp);
  2174. }
  2175. }
  2176. }
  2177. }