ularn_winx11.c 73 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885
  1. /* =============================================================================
  2. * PROGRAM: ularn
  3. * FILENAME: ularn_win.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 Windows 32 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 teh username and user id.
  55. *
  56. * =============================================================================
  57. */
  58. #include <X11/Xlib.h>
  59. #include <X11/keysym.h>
  60. #include <X11/xpm.h>
  61. #include <stdarg.h>
  62. #include <stdio.h>
  63. #include "cursor.bm"
  64. #include "header.h"
  65. #include "ularn_game.h"
  66. #include "x11_simple_menu.h"
  67. #include "config.h"
  68. #include "dungeon.h"
  69. #include "itm.h"
  70. #include "monster.h"
  71. #include "player.h"
  72. #include "ularn_win.h"
  73. // Default size of the ularn window in characters
  74. #define WINDOW_WIDTH 80
  75. #define WINDOW_HEIGHT 25
  76. #define SEPARATOR_WIDTH 8
  77. #define SEPARATOR_HEIGHT 8
  78. #define BORDER_SIZE 8
  79. /* =============================================================================
  80. * Exported variables
  81. */
  82. int nonap = 0;
  83. int nosignal = 0;
  84. char enable_scroll = 0;
  85. int yrepcount = 0;
  86. /* =============================================================================
  87. * Local variables
  88. */
  89. #define M_NONE 0
  90. #define M_SHIFT 1
  91. #define M_CTRL 2
  92. #define M_ASCII 255
  93. #define MAX_KEY_BINDINGS 3
  94. struct KeyCodeType {
  95. int VirtKey;
  96. int ModKey;
  97. };
  98. #define NUM_DIRS 8
  99. static ActionType DirActions[NUM_DIRS] = {
  100. ACTION_MOVE_WEST, ACTION_MOVE_EAST, ACTION_MOVE_SOUTH,
  101. ACTION_MOVE_NORTH, ACTION_MOVE_NORTHEAST, ACTION_MOVE_NORTHWEST,
  102. ACTION_MOVE_SOUTHEAST, ACTION_MOVE_SOUTHWEST};
  103. /* Default keymap */
  104. /* Allow up to MAX_KEY_BINDINGS per action */
  105. static struct KeyCodeType KeyMap[ACTION_COUNT][MAX_KEY_BINDINGS] = {
  106. {{0, 0}, {0, 0}, {0, 0}}, // ACTION_NULL
  107. {{'~', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_DIAG
  108. {{'h', M_ASCII},
  109. {XK_KP_Left, M_NONE},
  110. {XK_Left, M_NONE}}, // ACTION_MOVE_WEST
  111. {{'H', M_ASCII}, {XK_Left, M_SHIFT}, {0, 0}}, // ACTION_RUN_WEST
  112. {{'l', M_ASCII},
  113. {XK_KP_Right, M_NONE},
  114. {XK_Right, M_NONE}}, // ACTION_MOVE_EAST,
  115. {{'L', M_ASCII}, {XK_Right, M_SHIFT}, {0, 0}}, // ACTION_RUN_EAST,
  116. {{'j', M_ASCII},
  117. {XK_KP_Down, M_NONE},
  118. {XK_Down, M_NONE}}, // ACTION_MOVE_SOUTH,
  119. {{'J', M_ASCII}, {XK_Down, M_SHIFT}, {0, 0}}, // ACTION_RUN_SOUTH,
  120. {{'k', M_ASCII}, {XK_KP_Up, M_NONE}, {XK_Up, M_NONE}}, // ACTION_MOVE_NORTH,
  121. {{'K', M_ASCII}, {XK_Up, M_SHIFT}, {0, 0}}, // ACTION_RUN_NORTH,
  122. {{'u', M_ASCII},
  123. {XK_KP_Page_Up, M_NONE},
  124. {XK_Prior, M_NONE}}, // ACTION_MOVE_NORTHEAST,
  125. {{'U', M_ASCII}, {XK_Prior, M_SHIFT}, {0, 0}}, // ACTION_RUN_NORTHEAST,
  126. {{'y', M_ASCII},
  127. {XK_KP_Home, M_NONE},
  128. {XK_Home, M_NONE}}, // ACTION_MOVE_NORTHWEST,
  129. {{'Y', M_ASCII}, {XK_Home, M_SHIFT}, {0, 0}}, // ACTION_RUN_NORTHWEST,
  130. {{'n', M_ASCII},
  131. {XK_KP_Page_Down, M_NONE},
  132. {XK_Next, M_NONE}}, // ACTION_MOVE_SOUTHEAST,
  133. {{'N', M_ASCII}, {XK_Next, M_SHIFT}, {0, 0}}, // ACTION_RUN_SOUTHEAST,
  134. {{'b', M_ASCII},
  135. {XK_KP_End, M_NONE},
  136. {XK_End, M_NONE}}, // ACTION_MOVE_SOUTHWEST,
  137. {{'B', M_ASCII}, {XK_End, M_SHIFT}, {0, 0}}, // ACTION_RUN_SOUTHWEST,
  138. {{'.', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_WAIT,
  139. {{' ', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_NONE,
  140. {{'w', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_WIELD,
  141. {{'W', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_WEAR,
  142. {{'r', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_READ,
  143. {{'q', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_QUAFF,
  144. {{'d', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_DROP,
  145. {{'c', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_CAST_SPELL,
  146. {{'o', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_OPEN_DOOR
  147. {{'C', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_CLOSE_DOOR,
  148. {{'O', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_OPEN_CHEST
  149. {{'i', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_INVENTORY,
  150. {{'e', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_EAT_COOKIE,
  151. {{'\\', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_LIST_SPELLS,
  152. {{'?', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_HELP,
  153. {{'S', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_SAVE,
  154. {{'Z', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_TELEPORT,
  155. {{'^', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_IDENTIFY_TRAPS,
  156. {{'_', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_BECOME_CREATOR,
  157. {{'+', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_CREATE_ITEM,
  158. {{'-', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_TOGGLE_WIZARD,
  159. {{'`', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_DEBUG_MODE,
  160. {{'T', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_REMOVE_ARMOUR,
  161. {{'g', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_PACK_WEIGHT,
  162. {{'v', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_VERSION,
  163. {{'Q', M_ASCII}, {0, 0}, {0, 0}}, // ACTION_QUIT,
  164. {{'r', M_CTRL}, {0, 0}, {0, 0}}, // ACTION_REDRAW_SCREEN,
  165. {{'P', M_ASCII}, {0, 0}, {0, 0}} // ACTION_SHOW_TAX
  166. };
  167. static struct KeyCodeType RunKeyMap = {XK_KP_Begin, M_NONE};
  168. //
  169. // Variables for X11
  170. //
  171. #define MENU_GAME_SAVE 101
  172. #define MENU_GAME_QUIT 102
  173. #define MENU_ACTION_WAIT 201
  174. #define MENU_ACTION_WIELD 202
  175. #define MENU_ACTION_WEAR 203
  176. #define MENU_ACTION_TAKEOFF 204
  177. #define MENU_ACTION_QUAFF 205
  178. #define MENU_ACTION_READ 206
  179. #define MENU_ACTION_CAST 207
  180. #define MENU_ACTION_EAT 208
  181. #define MENU_ACTION_DROP 209
  182. #define MENU_ACTION_CLOSEDOOR 210
  183. #define MENU_SHOW_DISCOVERIES 301
  184. #define MENU_SHOW_INVENTORY 302
  185. #define MENU_SHOW_TAX 303
  186. #define MENU_SHOW_PACKWEIGHT 304
  187. #define MENU_DISPLAY_REDRAW 401
  188. #define MENU_DISPLAY_BEEP 402
  189. #define MENU_DISPLAY_FONT 403
  190. #define MENU_HELP_HELP 501
  191. #define MENU_HELP_VERSION 502
  192. #define MENU_HELP_ABOUT 503
  193. /* Help menu definitions */
  194. struct XMENU_Item Help_About_Item = /* unused */
  195. {"About", MENU_HELP_ABOUT, XMENU_UNCHECKED, NULL};
  196. struct XMENU_Item Help_Version_Item = {"Version", MENU_HELP_VERSION,
  197. XMENU_UNCHECKED, NULL};
  198. struct XMENU_Item Help_Help_Item = {"Help", MENU_HELP_HELP, XMENU_UNCHECKED,
  199. &Help_Version_Item};
  200. struct XMENU_Menu Help_Menu = {"Help", NULL, &Help_Help_Item, 0, 0, 0, 0};
  201. /* Display menu definitions */
  202. struct XMENU_Item Display_Font_Item = /* unused */
  203. {"Font", MENU_DISPLAY_FONT, XMENU_UNCHECKED, NULL};
  204. struct XMENU_Item Display_Beep_Item = {"Beep", MENU_DISPLAY_BEEP,
  205. XMENU_UNCHECKED, NULL};
  206. struct XMENU_Item Display_Redraw_Item = {"Redraw", MENU_DISPLAY_REDRAW,
  207. XMENU_UNCHECKED, &Display_Beep_Item};
  208. struct XMENU_Menu Display_Menu = {
  209. "Display", &Help_Menu, &Display_Redraw_Item, 0, 0, 0, 0};
  210. /* Show menu definitions */
  211. struct XMENU_Item Show_Packweight_Item = {"Pack weight", MENU_SHOW_PACKWEIGHT,
  212. XMENU_UNCHECKED, NULL};
  213. struct XMENU_Item Show_Tax_Item = {"Tax", MENU_SHOW_TAX, XMENU_UNCHECKED,
  214. &Show_Packweight_Item};
  215. struct XMENU_Item Show_Inventory_Item = {"Inventory", MENU_SHOW_INVENTORY,
  216. XMENU_UNCHECKED, &Show_Tax_Item};
  217. struct XMENU_Item Show_Discoveries_Item = {"Discoveries", MENU_SHOW_DISCOVERIES,
  218. XMENU_UNCHECKED,
  219. &Show_Inventory_Item};
  220. struct XMENU_Menu Show_Menu = {
  221. "Show", &Display_Menu, &Show_Discoveries_Item, 0, 0, 0, 0};
  222. /* Action Menu definitions */
  223. struct XMENU_Item Action_Closedoor_Item = {"Close door", MENU_ACTION_CLOSEDOOR,
  224. XMENU_UNCHECKED, NULL};
  225. struct XMENU_Item Action_Drop_Item = {"Drop", MENU_ACTION_DROP, XMENU_UNCHECKED,
  226. &Action_Closedoor_Item};
  227. struct XMENU_Item Action_Eat_Item = {"Eat", MENU_ACTION_EAT, XMENU_UNCHECKED,
  228. &Action_Drop_Item};
  229. struct XMENU_Item Action_Cast_Item = {"Cast", MENU_ACTION_CAST, XMENU_UNCHECKED,
  230. &Action_Eat_Item};
  231. struct XMENU_Item Action_Read_Item = {"Read", MENU_ACTION_READ, XMENU_UNCHECKED,
  232. &Action_Cast_Item};
  233. struct XMENU_Item Action_Quaff_Item = {"Quaff", MENU_ACTION_QUAFF,
  234. XMENU_UNCHECKED, &Action_Read_Item};
  235. struct XMENU_Item Action_Takeoff_Item = {"Take off", MENU_ACTION_TAKEOFF,
  236. XMENU_UNCHECKED, &Action_Quaff_Item};
  237. struct XMENU_Item Action_Wear_Item = {"Wear", MENU_ACTION_WEAR, XMENU_UNCHECKED,
  238. &Action_Takeoff_Item};
  239. struct XMENU_Item Action_Wield_Item = {"Wield", MENU_ACTION_WIELD,
  240. XMENU_UNCHECKED, &Action_Wear_Item};
  241. struct XMENU_Item Action_Wait_Item = {"Wait", MENU_ACTION_WAIT, XMENU_UNCHECKED,
  242. &Action_Wield_Item};
  243. struct XMENU_Menu Action_Menu = {"Action", &Show_Menu, &Action_Wait_Item, 0, 0,
  244. 0, 0};
  245. /* Game menu definitions */
  246. struct XMENU_Item Game_Quit_Item = {"Quit", MENU_GAME_QUIT, XMENU_UNCHECKED,
  247. NULL};
  248. struct XMENU_Item Game_Save_Item = {"Save", MENU_GAME_SAVE, XMENU_UNCHECKED,
  249. &Game_Quit_Item};
  250. struct XMENU_Menu Game_Menu = {"Game", &Action_Menu, &Game_Save_Item, 0, 0, 0,
  251. 0};
  252. int ularn_menu_height;
  253. #define INITIAL_WIDTH 400
  254. #define INITIAL_HEIGHT 300
  255. static Display *display = NULL;
  256. static int screen_num;
  257. static int screen_width;
  258. static int screen_height;
  259. static Window root_window = None;
  260. static Window ularn_window = None;
  261. static GC ularn_gc = None;
  262. static XGCValues gc_values;
  263. static unsigned long gc_values_mask;
  264. static unsigned long white_pixel;
  265. static unsigned long black_pixel;
  266. static Colormap colormap;
  267. static XColor LtGrey;
  268. static XColor MidGrey;
  269. static XColor DkGrey;
  270. static XColor Red;
  271. static XColor Green;
  272. static XColor Blue;
  273. static XFontStruct *font_info;
  274. char *font_name = "*-courier-medium-r-*-12-*";
  275. static Pixmap TilePixmap = None;
  276. static Pixmap TilePShape = None;
  277. static XpmAttributes TileAttributes;
  278. static Pixmap CursorPixmap = None;
  279. static int CaretActive = 0;
  280. static int TileWidth = 32;
  281. static int TileHeight = 32;
  282. static int CharHeight;
  283. static int CharWidth;
  284. static int CharAscent;
  285. static int LarnWindowWidth = INITIAL_WIDTH;
  286. static int LarnWindowHeight = INITIAL_HEIGHT;
  287. static int MinWindowWidth;
  288. static int MinWindowHeight;
  289. static int Runkey;
  290. static ActionType Event;
  291. static int GotChar;
  292. static char EventChar;
  293. //
  294. // Bitmaps for tiles
  295. //
  296. static char *TileFilename = LIBDIR "/vlarn_gfx.xpm";
  297. /* Tiles for different character classes, (female, male) */
  298. static int PlayerTiles[8][2] = {
  299. {165, 181}, /* Ogre */
  300. {166, 182}, /* Wizard */
  301. {167, 183}, /* Klingon */
  302. {168, 184}, /* Elf */
  303. {169, 185}, /* Rogue */
  304. {170, 186}, /* Adventurer */
  305. {171, 187}, /* Dwarf */
  306. {172, 188} /* Rambo */
  307. };
  308. #define TILE_CURSOR1 174
  309. #define TILE_CURSOR2 190
  310. #define WALL_TILES 352
  311. /* Tiles for directional effects */
  312. static int EffectTile[EFFECT_COUNT][9] = {
  313. {191, 198, 196, 194, 192, 195, 193, 197, 199},
  314. {191, 206, 204, 202, 200, 203, 201, 205, 207},
  315. {191, 214, 212, 210, 208, 211, 209, 213, 215},
  316. {191, 222, 220, 218, 216, 219, 217, 221, 223},
  317. {191, 230, 228, 226, 224, 227, 225, 229, 231}};
  318. #define MAX_MAGICFX_FRAME 8
  319. struct MagicEffectDataType {
  320. int Overlay; /* 0 = no overlay, 1 = overlay */
  321. int Frames; /* Number of frames in the effect */
  322. int Tile1[MAX_MAGICFX_FRAME]; /* The primary tile for this frame */
  323. int Tile2[MAX_MAGICFX_FRAME]; /* Only used for overlay effects */
  324. };
  325. static struct MagicEffectDataType magicfx_tile[MAGIC_COUNT] = {
  326. /* Sparkle */
  327. {1, /* Overlay this on current tile */
  328. 8,
  329. {240, 241, 242, 243, 244, 245, 246, 247},
  330. {248, 249, 250, 251, 252, 253, 254, 255}},
  331. /* Sleep */
  332. {0, 6, {256, 272, 288, 304, 320, 336, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  333. /* Web */
  334. {0, 6, {257, 273, 289, 305, 321, 337, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  335. /* Phantasmal forces */
  336. {0, 6, {258, 274, 290, 306, 322, 338, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  337. /* Cloud kill */
  338. {0, 6, {259, 275, 291, 307, 323, 339, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  339. /* Vaporize rock */
  340. {0, 6, {260, 276, 292, 308, 324, 340, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  341. /* Dehydrate */
  342. {0, 6, {261, 277, 293, 309, 325, 341, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  343. /* Drain life */
  344. {0, 6, {262, 278, 294, 310, 326, 342, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  345. /* Flood */
  346. {0, 6, {263, 279, 295, 311, 327, 343, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  347. /* Finger of death */
  348. {0, 6, {264, 280, 296, 312, 328, 344, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  349. /* Teleport away */
  350. {0, 6, {265, 281, 297, 313, 329, 345, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  351. /* Magic fire */
  352. {0, 6, {266, 282, 298, 314, 330, 346, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  353. /* Make wall */
  354. {0, 6, {267, 283, 299, 315, 331, 347, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  355. /* Summon demon */
  356. {0, 6, {268, 284, 300, 316, 332, 348, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
  357. /* Annihilate (scroll) */
  358. {0, 6, {269, 285, 301, 317, 333, 349, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}}};
  359. //
  360. // Current display mode
  361. //
  362. DisplayModeType CurrentDisplayMode = DISPLAY_TEXT;
  363. //
  364. // Map window position and size
  365. //
  366. static int MapLeft;
  367. static int MapTop;
  368. static int MapAreaLeft;
  369. static int MapAreaTop;
  370. static int MapWidth;
  371. static int MapHeight;
  372. static int MapTileLeft = 0;
  373. static int MapTileTop = 0;
  374. static int MapTileWidth;
  375. static int MapTileHeight;
  376. //
  377. // Status lines window position and size
  378. //
  379. static int StatusLeft;
  380. static int StatusTop;
  381. static int StatusWidth;
  382. static int StatusHeight;
  383. //
  384. // Effects window position and size
  385. //
  386. static int EffectsLeft;
  387. static int EffectsTop;
  388. static int EffectsWidth;
  389. static int EffectsHeight;
  390. //
  391. // Message window position and size
  392. //
  393. static int MessageLeft;
  394. static int MessageTop;
  395. static int MessageWidth;
  396. static int MessageHeight;
  397. //
  398. // Text window position, size
  399. //
  400. static int TextLeft;
  401. static int TextTop;
  402. static int TextWidth;
  403. static int TextHeight;
  404. static int ShowTextBorder;
  405. // =============================================================================
  406. // Text mode stuff
  407. //
  408. #define LINE_LENGTH 80
  409. typedef char TextLine[LINE_LENGTH + 1];
  410. typedef FormatType FormatLine[LINE_LENGTH + 1];
  411. //
  412. // Messages
  413. //
  414. #define MAX_MSG_LINES 5
  415. static TextLine MessageChr[MAX_MSG_LINES];
  416. static FormatLine MessageFmt[MAX_MSG_LINES];
  417. static FormatType CurrentMsgFormat;
  418. static int MsgCursorX = 1;
  419. static int MsgCursorY = 1;
  420. //
  421. // Text
  422. //
  423. #define MAX_TEXT_LINES 25
  424. #define TEXT_LINE_LENGTH 80
  425. static TextLine TextChr[MAX_TEXT_LINES];
  426. static FormatLine TextFmt[MAX_TEXT_LINES];
  427. static FormatType CurrentTextFormat;
  428. static int TextCursorX = 1;
  429. static int TextCursorY = 1;
  430. //
  431. // Generalised text buffer
  432. // Top left corner is x=1, y=1
  433. //
  434. static TextLine *Text;
  435. static FormatLine *Format;
  436. static FormatType CurrentFormat;
  437. static int CursorX = 1;
  438. static int CursorY = 1;
  439. static int MaxLine;
  440. static int TTop;
  441. static int TLeft;
  442. static int TWidth;
  443. static int THeight;
  444. //
  445. // The monster to use for showing mimics. Changes every 10 turns.
  446. //
  447. static int mimicmonst = MIMIC;
  448. /* =============================================================================
  449. * Local functions
  450. */
  451. /* =============================================================================
  452. * FUNCTION: calc_scroll
  453. *
  454. * DESCRIPTION:
  455. * Calculate the new scroll position of the map based on the player's current
  456. * position.
  457. *
  458. * PARAMETERS:
  459. *
  460. * None.
  461. *
  462. * RETURN VALUE:
  463. *
  464. * true if the new scroll position differs from the previous scroll position.
  465. */
  466. static int calc_scroll(void) {
  467. int ox, oy;
  468. ox = MapTileLeft;
  469. oy = MapTileTop;
  470. if (MapTileHeight < MAXY) {
  471. MapTileTop = playery - MapTileHeight / 2;
  472. if (MapTileTop < 0)
  473. MapTileTop = 0;
  474. if ((MapTileTop + MapTileHeight) > MAXY)
  475. MapTileTop = MAXY - MapTileHeight;
  476. } else
  477. MapTileTop = 0;
  478. if (MapTileWidth < MAXX) {
  479. MapTileLeft = playerx - MapTileWidth / 2;
  480. if (MapTileLeft < 0)
  481. MapTileLeft = 0;
  482. if ((MapTileLeft + MapTileWidth) > MAXX)
  483. MapTileLeft = MAXX - MapTileWidth;
  484. } else
  485. MapTileLeft = 0;
  486. //
  487. // return true if the map requires scrolling
  488. //
  489. return (MapTileLeft != ox) || (MapTileTop != oy);
  490. }
  491. /* =============================================================================
  492. * FUNCTION: CalcMinWindowSize
  493. *
  494. * DESCRIPTION:
  495. * Calculate the minimum window size.
  496. * The new minimum windows size is stored in MinWindowWidth and MinWindowHeight.
  497. * If the current window size is smaller than this then it is resized.
  498. *
  499. * PARAMETERS:
  500. *
  501. * None.
  502. *
  503. * RETURN VALUE:
  504. *
  505. * None.
  506. */
  507. static void CalcMinWindowSize(void) {
  508. XSizeHints size_hints;
  509. CharWidth = font_info->max_bounds.width;
  510. CharHeight = font_info->max_bounds.ascent + font_info->max_bounds.descent;
  511. CharAscent = font_info->max_bounds.ascent;
  512. MinWindowWidth = WINDOW_WIDTH * CharWidth;
  513. MinWindowHeight =
  514. WINDOW_HEIGHT * CharHeight + 2 * SEPARATOR_HEIGHT + ularn_menu_height;
  515. //
  516. // Update the window size
  517. //
  518. if (MinWindowWidth > LarnWindowWidth)
  519. LarnWindowWidth = MinWindowWidth;
  520. if (MinWindowHeight > LarnWindowHeight)
  521. LarnWindowHeight = MinWindowHeight;
  522. size_hints.flags = PMinSize | PBaseSize;
  523. size_hints.min_width = MinWindowWidth;
  524. size_hints.min_height = MinWindowHeight;
  525. size_hints.base_width = LarnWindowWidth;
  526. size_hints.base_height = LarnWindowHeight;
  527. XSetNormalHints(display, ularn_window, &size_hints);
  528. XResizeWindow(display, ularn_window, LarnWindowWidth, LarnWindowHeight);
  529. }
  530. /*
  531. * Repaint flag to force redraw of everything, not just deltas
  532. */
  533. static int Repaint = 0;
  534. /* =============================================================================
  535. * FUNCTION: PaintStatus
  536. *
  537. * DESCRIPTION:
  538. * Paint the status area.
  539. *
  540. * PARAMETERS:
  541. *
  542. * None.
  543. *
  544. * RETURN VALUE:
  545. *
  546. * None.
  547. */
  548. static void PaintStatus(void) {
  549. char Line[81];
  550. char Buf[81];
  551. int i;
  552. XSetForeground(display, ularn_gc, white_pixel);
  553. XSetBackground(display, ularn_gc, black_pixel);
  554. XSetFillStyle(display, ularn_gc, FillSolid);
  555. XFillRectangle(display, ularn_window, ularn_gc, StatusLeft, StatusTop,
  556. StatusWidth, StatusHeight);
  557. XSetForeground(display, ularn_gc, black_pixel);
  558. XSetBackground(display, ularn_gc, white_pixel);
  559. XSetFillStyle(display, ularn_gc, FillSolid);
  560. //
  561. // Build the top status line
  562. //
  563. Line[0] = 0;
  564. /* Spells */
  565. if (c[SPELLMAX] > 99)
  566. sprintf(Buf, "Spells:%3ld(%3ld)", c[SPELLS], c[SPELLMAX]);
  567. else
  568. sprintf(Buf, "Spells:%3ld(%2ld) ", c[SPELLS], c[SPELLMAX]);
  569. strcat(Line, Buf);
  570. /* AC, WC */
  571. sprintf(Buf, " AC: %-3ld WC: %-3ld Level", c[AC], c[WCLASS]);
  572. strcat(Line, Buf);
  573. /* Level */
  574. if (c[LEVEL] > 99)
  575. sprintf(Buf, "%3ld", c[LEVEL]);
  576. else
  577. sprintf(Buf, " %-2ld", c[LEVEL]);
  578. strcat(Line, Buf);
  579. /* Exp, class */
  580. sprintf(Buf, " Exp: %-9ld %s", c[EXPERIENCE], class[c[LEVEL] - 1]);
  581. strcat(Line, Buf);
  582. XDrawString(display, ularn_window, ularn_gc, StatusLeft,
  583. StatusTop + CharAscent, Line, strlen(Line));
  584. //
  585. // Format the second line of the status
  586. //
  587. sprintf(Buf, "%ld (%ld)", c[HP], c[HPMAX]);
  588. sprintf(Line,
  589. "HP: %11s STR=%-2ld INT=%-2ld WIS=%-2ld CON=%-2ld DEX=%-2ld "
  590. "CHA=%-2ld LV:",
  591. Buf, c[STRENGTH] + c[STREXTRA], c[INTELLIGENCE], c[WISDOM],
  592. c[CONSTITUTION], c[DEXTERITY], c[CHARISMA]);
  593. if ((level == 0) || (wizard))
  594. c[TELEFLAG] = 0;
  595. if (c[TELEFLAG])
  596. strcat(Line, " ?");
  597. else
  598. strcat(Line, levelname[level]);
  599. sprintf(Buf, " Gold: %-8ld", c[GOLD]);
  600. strcat(Line, Buf);
  601. XDrawString(display, ularn_window, ularn_gc, StatusLeft,
  602. StatusTop + CharHeight + CharAscent, Line, strlen(Line));
  603. //
  604. // Mark all character values as displayed.
  605. //
  606. c[TMP] = c[STRENGTH] + c[STREXTRA];
  607. for (i = 0; i < 100; i++)
  608. cbak[i] = c[i];
  609. }
  610. /* Effects strings */
  611. static struct bot_side_def {
  612. int typ;
  613. char *string;
  614. } bot_data[] = {{STEALTH, "Stealth "}, {UNDEADPRO, "Undead Pro"},
  615. {SPIRITPRO, "Spirit Pro"}, {CHARMCOUNT, "Charm "},
  616. {TIMESTOP, "Time Stop "}, {HOLDMONST, "Hold Monst"},
  617. {GIANTSTR, "Giant Str "}, {FIRERESISTANCE, "Fire Resit"},
  618. {DEXCOUNT, "Dexterity "}, {STRCOUNT, "Strength "},
  619. {SCAREMONST, "Scare "}, {HASTESELF, "Haste Self"},
  620. {CANCELLATION, "Cancel "}, {INVISIBILITY, "Invisible "},
  621. {ALTPRO, "Protect 3 "}, {PROTECTIONTIME, "Protect 2 "},
  622. {WTW, "Wall-Walk "}};
  623. /* =============================================================================
  624. * FUNCTION: PaintEffects
  625. *
  626. * DESCRIPTION:
  627. * Paint the effects display.
  628. *
  629. * PARAMETERS:
  630. *
  631. * None.
  632. *
  633. * RETURN VALUE:
  634. *
  635. * None.
  636. */
  637. static void PaintEffects(void) {
  638. int i, idx;
  639. int WasSet;
  640. int IsSet;
  641. if (Repaint) {
  642. XSetForeground(display, ularn_gc, white_pixel);
  643. XSetBackground(display, ularn_gc, black_pixel);
  644. XSetFillStyle(display, ularn_gc, FillSolid);
  645. XFillRectangle(display, ularn_window, ularn_gc, EffectsLeft, EffectsTop,
  646. EffectsWidth, EffectsHeight);
  647. }
  648. for (i = 0; i < 17; i++) {
  649. idx = bot_data[i].typ;
  650. WasSet = (cbak[idx] != 0);
  651. IsSet = (c[idx] != 0);
  652. if ((Repaint) || (IsSet != WasSet)) {
  653. if (IsSet) {
  654. XSetForeground(display, ularn_gc, black_pixel);
  655. XSetBackground(display, ularn_gc, white_pixel);
  656. XSetFillStyle(display, ularn_gc, FillSolid);
  657. XDrawString(display, ularn_window, ularn_gc, EffectsLeft,
  658. EffectsTop + i * CharHeight + CharAscent,
  659. bot_data[i].string, strlen(bot_data[i].string));
  660. } else {
  661. XSetForeground(display, ularn_gc, white_pixel);
  662. XSetBackground(display, ularn_gc, black_pixel);
  663. XSetFillStyle(display, ularn_gc, FillSolid);
  664. XFillRectangle(display, ularn_window, ularn_gc, EffectsLeft,
  665. EffectsTop + i * CharHeight, EffectsWidth, CharHeight);
  666. }
  667. }
  668. cbak[idx] = c[idx];
  669. }
  670. }
  671. /* =============================================================================
  672. * FUNCTION: GetTile
  673. *
  674. * DESCRIPTION:
  675. * Get the tile to be displayed for a location on the map.
  676. *
  677. * PARAMETERS:
  678. *
  679. * x : The x coordinate for the tile
  680. *
  681. * y : The y coordiante for the tile
  682. *
  683. * TileId : This is set to the tile to be displayed for (x, y).
  684. *
  685. * RETURN VALUE:
  686. *
  687. * None.
  688. */
  689. static void GetTile(int x, int y, int *TileId) {
  690. MonsterIdType k;
  691. if ((x == playerx) && (y == playery) && (c[BLINDCOUNT] == 0)) {
  692. //
  693. // This is the square containing the player and the players isn't
  694. // blind, so return the player tile.
  695. //
  696. *TileId = PlayerTiles[class_num][(int)sex];
  697. return;
  698. }
  699. //
  700. // Work out what is here
  701. //
  702. if (know[x][y] == OUNKNOWN) {
  703. //
  704. // The player doesn't know what is at this position.
  705. //
  706. *TileId = objtilelist[OUNKNOWN];
  707. } else {
  708. k = mitem[x][y].mon;
  709. if (k != 0) {
  710. if ((c[BLINDCOUNT] == 0) && (((stealth[x][y] & STEALTH_SEEN) != 0) ||
  711. ((stealth[x][y] & STEALTH_AWAKE) != 0))) {
  712. //
  713. // There is a monster here and the player is not blind and the
  714. // monster is seen or awake.
  715. //
  716. if (k == MIMIC) {
  717. if ((gtime % 10) == 0)
  718. while ((mimicmonst = rnd(MAXMONST)) == INVISIBLESTALKER)
  719. ;
  720. *TileId = monsttilelist[mimicmonst];
  721. } else if ((k == INVISIBLESTALKER) && (c[SEEINVISIBLE] == 0))
  722. *TileId = objtilelist[(int)know[x][y]];
  723. else if ((k >= DEMONLORD) && (k <= LUCIFER) && (c[EYEOFLARN] == 0))
  724. /* demons are invisible if not have the eye */
  725. *TileId = objtilelist[(int)know[x][y]];
  726. else
  727. *TileId = monsttilelist[k];
  728. } /* can see monster */
  729. else
  730. /*
  731. * The monster at this location is not known to the player, so show
  732. * the tile for the item at this location
  733. */
  734. *TileId = objtilelist[(int)know[x][y]];
  735. } /* monster here */
  736. else {
  737. k = know[x][y];
  738. *TileId = objtilelist[k];
  739. }
  740. }
  741. /* Handle walls */
  742. if (*TileId == objtilelist[OWALL])
  743. *TileId = WALL_TILES + iarg[x][y];
  744. }
  745. /* =============================================================================
  746. * FUNCTION: PaintMap
  747. *
  748. * DESCRIPTION:
  749. * Repaint the map.
  750. *
  751. * PARAMETERS:
  752. *
  753. * None.
  754. *
  755. * RETURN VALUE:
  756. *
  757. * None.
  758. */
  759. static void PaintMap(void) {
  760. int x, y;
  761. int sx, sy;
  762. int mx, my;
  763. int TileId;
  764. int TileX;
  765. int TileY;
  766. if (Repaint) {
  767. XSetForeground(display, ularn_gc, black_pixel);
  768. XFillRectangle(display, ularn_window, ularn_gc, MapAreaLeft, MapAreaTop,
  769. MapWidth, MapHeight);
  770. }
  771. mx = MapTileLeft + MapTileWidth;
  772. my = MapTileTop + MapTileHeight;
  773. if (my > MAXY)
  774. my = MAXY;
  775. if (mx > MAXX)
  776. mx = MAXX;
  777. sx = 0;
  778. for (x = MapTileLeft; x < mx; x++) {
  779. sy = 0;
  780. for (y = MapTileTop; y < my; y++) {
  781. GetTile(x, y, &TileId);
  782. TileX = (TileId % 16) * TileWidth;
  783. TileY = (TileId / 16) * TileHeight;
  784. XCopyArea(display, TilePixmap, ularn_window, ularn_gc, TileX, TileY,
  785. TileWidth, TileHeight, MapLeft + sx * TileWidth,
  786. MapTop + sy * TileHeight);
  787. sy++;
  788. }
  789. sx++;
  790. }
  791. sx = playerx - MapTileLeft;
  792. sy = playery - MapTileTop;
  793. if ((sx >= 0) && (sx < MapTileWidth) && (sy >= 0) && (sy < MapTileHeight)) {
  794. TileId = TILE_CURSOR1;
  795. TileX = (TileId % 16) * TileWidth;
  796. TileY = (TileId / 16) * TileHeight;
  797. XSetClipOrigin(display, ularn_gc, MapLeft + sx * TileWidth - TileX,
  798. MapTop + sy * TileHeight - TileY);
  799. XSetClipMask(display, ularn_gc, TilePShape);
  800. XCopyArea(display, TilePixmap, ularn_window, ularn_gc, TileX, TileY,
  801. TileWidth, TileHeight, MapLeft + sx * TileWidth,
  802. MapTop + sy * TileHeight);
  803. XSetClipOrigin(display, ularn_gc, 0, 0);
  804. XSetClipMask(display, ularn_gc, None);
  805. }
  806. }
  807. /* =============================================================================
  808. * FUNCTION: PaintTextWindow
  809. *
  810. * DESCRIPTION:
  811. * Repaint the window in text mode.
  812. *
  813. * PARAMETERS:
  814. *
  815. * None.
  816. *
  817. * RETURN VALUE:
  818. *
  819. * None.
  820. */
  821. static void PaintTextWindow(void) {
  822. int sx, ex, y;
  823. FormatType Fmt;
  824. int FillX, FillY;
  825. int FillWidth, FillHeight;
  826. XGCValues values;
  827. FillX = TLeft;
  828. FillY = TTop;
  829. FillWidth = TWidth;
  830. FillHeight = THeight;
  831. if (CurrentDisplayMode == DISPLAY_TEXT) {
  832. if (ShowTextBorder) {
  833. //
  834. // Clear the drawable area
  835. //
  836. FillX = 0;
  837. FillY = ularn_menu_height;
  838. FillWidth = LarnWindowWidth;
  839. FillHeight = LarnWindowHeight - ularn_menu_height;
  840. XSetForeground(display, ularn_gc, black_pixel);
  841. XSetBackground(display, ularn_gc, white_pixel);
  842. XSetFillStyle(display, ularn_gc, FillSolid);
  843. XFillRectangle(display, ularn_window, ularn_gc, FillX, FillY, FillWidth,
  844. FillHeight);
  845. XSetForeground(display, ularn_gc, white_pixel);
  846. XSetBackground(display, ularn_gc, black_pixel);
  847. values.line_width = 2;
  848. XChangeGC(display, ularn_gc, GCLineWidth, &values);
  849. XDrawArc(display, ularn_window, ularn_gc, TLeft - 8, TTop - 8, 16, 16,
  850. 90 * 64, 90 * 64);
  851. XDrawArc(display, ularn_window, ularn_gc, TLeft - 8, TTop + THeight - 8,
  852. 16, 16, 180 * 64, 90 * 64);
  853. XDrawArc(display, ularn_window, ularn_gc, TLeft + TWidth - 8, TTop - 8,
  854. 16, 16, 0 * 64, 90 * 64);
  855. XDrawArc(display, ularn_window, ularn_gc, TLeft + TWidth - 8,
  856. TTop + THeight - 8, 16, 16, 270 * 64, 90 * 64);
  857. XDrawLine(display, ularn_window, ularn_gc, TLeft, TTop - 8,
  858. TLeft + TWidth, TTop - 8);
  859. XDrawLine(display, ularn_window, ularn_gc, TLeft, TTop + THeight + 8,
  860. TLeft + TWidth, TTop + THeight + 8);
  861. XDrawLine(display, ularn_window, ularn_gc, TLeft - 8, TTop, TLeft - 8,
  862. TTop + THeight);
  863. XDrawLine(display, ularn_window, ularn_gc, TLeft + TWidth + 8, TTop,
  864. TLeft + TWidth + 8, TTop + THeight);
  865. values.line_width = 0;
  866. XChangeGC(display, ularn_gc, GCLineWidth, &values);
  867. FillX = TLeft;
  868. FillY = TTop;
  869. FillWidth = TWidth;
  870. FillHeight = THeight;
  871. } else {
  872. //
  873. // Not enough space around the text area for a border
  874. // Fill the entire drawable area
  875. //
  876. FillX = 0;
  877. FillY = ularn_menu_height;
  878. FillWidth = LarnWindowWidth;
  879. FillHeight = LarnWindowHeight - ularn_menu_height;
  880. }
  881. }
  882. XSetForeground(display, ularn_gc, white_pixel);
  883. XSetBackground(display, ularn_gc, black_pixel);
  884. XSetFillStyle(display, ularn_gc, FillSolid);
  885. XFillRectangle(display, ularn_window, ularn_gc, FillX, FillY, FillWidth,
  886. FillHeight);
  887. XSetForeground(display, ularn_gc, black_pixel);
  888. XSetBackground(display, ularn_gc, white_pixel);
  889. XSetFillStyle(display, ularn_gc, FillSolid);
  890. for (y = 0; y < MaxLine; y++) {
  891. sx = 0;
  892. while (sx < LINE_LENGTH) {
  893. Fmt = Format[y][sx];
  894. ex = sx;
  895. while ((ex < LINE_LENGTH) && (Format[y][ex] == Fmt))
  896. ex++;
  897. switch (Fmt) {
  898. case FORMAT_NORMAL:
  899. XSetForeground(display, ularn_gc, black_pixel);
  900. break;
  901. case FORMAT_STANDOUT:
  902. XSetForeground(display, ularn_gc, Red.pixel);
  903. break;
  904. case FORMAT_STANDOUT2:
  905. XSetForeground(display, ularn_gc, Green.pixel);
  906. break;
  907. case FORMAT_STANDOUT3:
  908. XSetForeground(display, ularn_gc, Blue.pixel);
  909. break;
  910. default:
  911. break;
  912. }
  913. XDrawString(display, ularn_window, ularn_gc, TLeft + sx * CharWidth,
  914. TTop + y * CharHeight + CharAscent, Text[y] + sx, ex - sx);
  915. sx = ex;
  916. }
  917. }
  918. }
  919. /* =============================================================================
  920. * FUNCTION: PaintMapWindow
  921. *
  922. * DESCRIPTION:
  923. * Repaint the window in map mode
  924. *
  925. * PARAMETERS:
  926. *
  927. * None.
  928. *
  929. * RETURN VALUE:
  930. *
  931. * None.
  932. */
  933. static void PaintMapWindow(void) {
  934. //
  935. // Draw separators between the different window areas
  936. //
  937. //
  938. // Message area
  939. //
  940. XSetForeground(display, ularn_gc, LtGrey.pixel);
  941. XFillRectangle(display, ularn_window, ularn_gc, MessageLeft,
  942. MessageTop - SEPARATOR_HEIGHT, MessageWidth, 2);
  943. XSetForeground(display, ularn_gc, MidGrey.pixel);
  944. XFillRectangle(display, ularn_window, ularn_gc, MessageLeft,
  945. MessageTop - SEPARATOR_HEIGHT + 2, MessageWidth, 4);
  946. XSetForeground(display, ularn_gc, DkGrey.pixel);
  947. XFillRectangle(display, ularn_window, ularn_gc, MessageLeft,
  948. MessageTop - SEPARATOR_HEIGHT + 6, MessageWidth, 2);
  949. //
  950. // Status area
  951. //
  952. XSetForeground(display, ularn_gc, LtGrey.pixel);
  953. XFillRectangle(display, ularn_window, ularn_gc, StatusLeft,
  954. StatusTop - SEPARATOR_HEIGHT, StatusWidth, 2);
  955. XSetForeground(display, ularn_gc, MidGrey.pixel);
  956. XFillRectangle(display, ularn_window, ularn_gc, StatusLeft,
  957. StatusTop - SEPARATOR_HEIGHT + 2, StatusWidth, 4);
  958. XSetForeground(display, ularn_gc, DkGrey.pixel);
  959. XFillRectangle(display, ularn_window, ularn_gc, StatusLeft,
  960. StatusTop - SEPARATOR_HEIGHT + 6, StatusWidth, 2);
  961. //
  962. // Effects area
  963. //
  964. XSetForeground(display, ularn_gc, LtGrey.pixel);
  965. XFillRectangle(display, ularn_window, ularn_gc, EffectsLeft - SEPARATOR_WIDTH,
  966. EffectsTop, 2, EffectsHeight);
  967. XSetForeground(display, ularn_gc, MidGrey.pixel);
  968. XFillRectangle(display, ularn_window, ularn_gc,
  969. EffectsLeft - SEPARATOR_WIDTH + 2, EffectsTop, 4,
  970. EffectsHeight + 2);
  971. XSetForeground(display, ularn_gc, DkGrey.pixel);
  972. XFillRectangle(display, ularn_window, ularn_gc,
  973. EffectsLeft - SEPARATOR_WIDTH + 6, EffectsTop, 2,
  974. EffectsHeight);
  975. PaintStatus();
  976. PaintEffects();
  977. PaintMap();
  978. PaintTextWindow();
  979. }
  980. /* =============================================================================
  981. * FUNCTION: PaintWindow
  982. *
  983. * DESCRIPTION:
  984. * Repaint the window.
  985. *
  986. * PARAMETERS:
  987. *
  988. * None.
  989. *
  990. * RETURN VALUE:
  991. *
  992. * None.
  993. */
  994. static void PaintWindow(void) {
  995. Repaint = 1;
  996. XMENU_Redraw();
  997. if (CurrentDisplayMode == DISPLAY_MAP)
  998. PaintMapWindow();
  999. else
  1000. PaintTextWindow();
  1001. Repaint = 0;
  1002. }
  1003. /* =============================================================================
  1004. * FUNCTION: Resize
  1005. *
  1006. * DESCRIPTION:
  1007. * This procedure handles resizing the window in response to any event that
  1008. * requires the sub-window size and position to be recalculated.
  1009. *
  1010. * PARAMETERS:
  1011. *
  1012. * None.
  1013. *
  1014. * RETURN VALUE:
  1015. *
  1016. * None.
  1017. */
  1018. static void Resize(void) {
  1019. XWindowAttributes win_attr;
  1020. int ClientWidth;
  1021. int ClientHeight;
  1022. /* XXX trn - check status rc return val */
  1023. /*Status rc;
  1024. rc = */
  1025. XGetWindowAttributes(display, ularn_window, &win_attr);
  1026. LarnWindowWidth = win_attr.width;
  1027. LarnWindowHeight = win_attr.height;
  1028. ClientWidth = LarnWindowWidth;
  1029. ClientHeight = LarnWindowHeight;
  1030. //
  1031. // Calculate the message window size and position
  1032. //
  1033. MessageWidth = ClientWidth;
  1034. MessageHeight = CharHeight * MAX_MSG_LINES;
  1035. MessageLeft = 0;
  1036. MessageTop = ClientHeight - MessageHeight - 1;
  1037. //
  1038. // Calculate the Status window size and position
  1039. //
  1040. StatusLeft = 0;
  1041. StatusTop = (MessageTop - SEPARATOR_HEIGHT) - CharHeight * 2;
  1042. StatusWidth = ClientWidth;
  1043. StatusHeight = CharHeight * 2;
  1044. //
  1045. // Calculate the Effects window size and position
  1046. //
  1047. EffectsLeft = ClientWidth - CharWidth * 10;
  1048. EffectsTop = ularn_menu_height;
  1049. EffectsWidth = CharWidth * 10;
  1050. EffectsHeight = StatusTop - SEPARATOR_HEIGHT - EffectsTop;
  1051. //
  1052. // Calculate the size and position of the map window
  1053. //
  1054. MapAreaLeft = 0;
  1055. MapAreaTop = ularn_menu_height;
  1056. MapLeft = 0;
  1057. MapTop = MapAreaTop;
  1058. MapWidth = EffectsLeft - SEPARATOR_WIDTH;
  1059. MapHeight = StatusTop - SEPARATOR_HEIGHT - MapAreaTop;
  1060. MapTileWidth = MapWidth / TileWidth;
  1061. MapTileHeight = MapHeight / TileHeight;
  1062. //
  1063. // Calculate the size and position of the text window
  1064. //
  1065. TextWidth = CharWidth * LINE_LENGTH;
  1066. TextHeight = CharHeight * MAX_TEXT_LINES;
  1067. TextLeft = (ClientWidth - TextWidth) / 2;
  1068. TextTop =
  1069. ularn_menu_height + (ClientHeight - TextHeight - ularn_menu_height) / 2;
  1070. //
  1071. // Check if should draw a border around the text page when it is displayed
  1072. //
  1073. ShowTextBorder = (TextLeft >= BORDER_SIZE) &&
  1074. (TextTop >= (ularn_menu_height + BORDER_SIZE));
  1075. //
  1076. // If the map window is bigger than required to display the map, then centre
  1077. // the map in the window.
  1078. //
  1079. if (MapTileWidth > MAXX) {
  1080. MapTileWidth = MAXX;
  1081. MapLeft = (MapWidth - MapTileWidth * TileWidth) / 2;
  1082. }
  1083. if (MapTileHeight > MAXY) {
  1084. MapTileHeight = MAXY;
  1085. MapTop = MapAreaTop + (MapHeight - MapTileHeight * TileHeight) / 2;
  1086. }
  1087. if (CurrentDisplayMode == DISPLAY_MAP) {
  1088. TLeft = MessageLeft;
  1089. TTop = MessageTop;
  1090. TWidth = MessageWidth;
  1091. THeight = MessageHeight;
  1092. } else {
  1093. TLeft = TextLeft;
  1094. TTop = TextTop;
  1095. TWidth = TextWidth;
  1096. THeight = TextHeight;
  1097. }
  1098. //
  1099. // calculate the map scroll position for the current player position
  1100. //
  1101. calc_scroll();
  1102. //
  1103. // Force the window to redraw
  1104. //
  1105. PaintWindow();
  1106. if (CaretActive) {
  1107. XSetForeground(display, ularn_gc, black_pixel);
  1108. XSetClipOrigin(display, ularn_gc, TLeft + (CursorX - 1) * CharWidth,
  1109. TTop + (CursorY - 1) * CharHeight + CharAscent);
  1110. XSetClipMask(display, ularn_gc, CursorPixmap);
  1111. XCopyPlane(display, CursorPixmap, ularn_window, ularn_gc, 0, 0,
  1112. cursor_width, cursor_height, TLeft + (CursorX - 1) * CharWidth,
  1113. TTop + (CursorY - 1) * CharHeight + CharAscent, 1);
  1114. XSetClipOrigin(display, ularn_gc, 0, 0);
  1115. XSetClipMask(display, ularn_gc, None);
  1116. }
  1117. }
  1118. /* =============================================================================
  1119. * FUNCTION: handle_event
  1120. *
  1121. * DESCRIPTION:
  1122. * This procedure handles the processing for X events.
  1123. *
  1124. * PARAMETERS:
  1125. *
  1126. * event : The X event to process.
  1127. *
  1128. * RETURN VALUE:
  1129. *
  1130. * None.
  1131. */
  1132. static void handle_event(XEvent *event) {
  1133. int MenuId;
  1134. /* Handle menu input */
  1135. MenuId = XMENU_HandleEvent(event);
  1136. if (MenuId >= 0) {
  1137. switch (MenuId) {
  1138. case MENU_GAME_SAVE:
  1139. Event = ACTION_SAVE;
  1140. break;
  1141. case MENU_GAME_QUIT:
  1142. Event = ACTION_QUIT;
  1143. break;
  1144. case MENU_ACTION_WAIT:
  1145. Event = ACTION_WAIT;
  1146. break;
  1147. case MENU_ACTION_WIELD:
  1148. Event = ACTION_WIELD;
  1149. break;
  1150. case MENU_ACTION_WEAR:
  1151. Event = ACTION_WEAR;
  1152. break;
  1153. case MENU_ACTION_TAKEOFF:
  1154. Event = ACTION_REMOVE_ARMOUR;
  1155. break;
  1156. case MENU_ACTION_QUAFF:
  1157. Event = ACTION_QUAFF;
  1158. break;
  1159. case MENU_ACTION_READ:
  1160. Event = ACTION_READ;
  1161. break;
  1162. case MENU_ACTION_CAST:
  1163. Event = ACTION_CAST_SPELL;
  1164. break;
  1165. case MENU_ACTION_EAT:
  1166. Event = ACTION_EAT_COOKIE;
  1167. break;
  1168. case MENU_ACTION_DROP:
  1169. Event = ACTION_DROP;
  1170. break;
  1171. case MENU_ACTION_CLOSEDOOR:
  1172. Event = ACTION_CLOSE_DOOR;
  1173. break;
  1174. case MENU_SHOW_DISCOVERIES:
  1175. Event = ACTION_LIST_SPELLS;
  1176. break;
  1177. case MENU_SHOW_INVENTORY:
  1178. Event = ACTION_INVENTORY;
  1179. break;
  1180. case MENU_SHOW_TAX:
  1181. Event = ACTION_SHOW_TAX;
  1182. break;
  1183. case MENU_SHOW_PACKWEIGHT:
  1184. Event = ACTION_PACK_WEIGHT;
  1185. break;
  1186. case MENU_DISPLAY_REDRAW:
  1187. Event = ACTION_REDRAW_SCREEN;
  1188. break;
  1189. case MENU_DISPLAY_BEEP:
  1190. nobeep = !nobeep;
  1191. /* Set menu checkmarks */
  1192. if (nobeep)
  1193. XMENU_SetCheck(MENU_DISPLAY_BEEP, XMENU_UNCHECKED);
  1194. else
  1195. XMENU_SetCheck(MENU_DISPLAY_BEEP, XMENU_CHECKED);
  1196. break;
  1197. case MENU_DISPLAY_FONT:
  1198. break;
  1199. case MENU_HELP_HELP:
  1200. Event = ACTION_HELP;
  1201. break;
  1202. case MENU_HELP_VERSION:
  1203. Event = ACTION_VERSION;
  1204. break;
  1205. case MENU_HELP_ABOUT:
  1206. break;
  1207. default:
  1208. break;
  1209. }
  1210. return;
  1211. }
  1212. //
  1213. // What is the message
  1214. //
  1215. switch (event->type) {
  1216. case Expose:
  1217. if (event->xexpose.count == 0)
  1218. PaintWindow();
  1219. break;
  1220. case ConfigureNotify:
  1221. Resize();
  1222. break;
  1223. case KeyPress: {
  1224. ActionType Action;
  1225. int ModKey = 0;
  1226. int Found = 0;
  1227. KeySym key_symbol;
  1228. XComposeStatus compose;
  1229. char KeyString[40];
  1230. int i;
  1231. XLookupString(&(event->xkey), KeyString, 40, &key_symbol, &compose);
  1232. if ((event->xkey.state & ShiftMask) != 0)
  1233. ModKey |= M_SHIFT;
  1234. if ((event->xkey.state & ControlMask) != 0)
  1235. ModKey |= M_CTRL;
  1236. /* Get ASCII character */
  1237. EventChar = KeyString[0];
  1238. GotChar = (EventChar != 0);
  1239. /* Decode key press as a ULarn Action */
  1240. Action = ACTION_NULL;
  1241. /* Check virtual key bindings */
  1242. while ((Action < ACTION_COUNT) && (!Found)) {
  1243. for (i = 0; i < MAX_KEY_BINDINGS; i++) {
  1244. if (KeyMap[Action][i].ModKey != M_ASCII) {
  1245. /* Virtual key binding */
  1246. if ((key_symbol == KeyMap[Action][i].VirtKey) &&
  1247. (KeyMap[Action][i].ModKey == ModKey))
  1248. Found = 1;
  1249. }
  1250. }
  1251. if (!Found)
  1252. Action++;
  1253. }
  1254. /*
  1255. * Check ASCII key bindings if no virtual key matches and
  1256. * got a valid ASCII char
  1257. */
  1258. if (!Found && GotChar) {
  1259. Action = ACTION_NULL;
  1260. while ((Action < ACTION_COUNT) && (!Found)) {
  1261. for (i = 0; i < MAX_KEY_BINDINGS; i++) {
  1262. if (KeyMap[Action][i].ModKey == M_ASCII) {
  1263. /* ASCII key binding */
  1264. if (EventChar == KeyMap[Action][i].VirtKey)
  1265. Found = 1;
  1266. }
  1267. }
  1268. if (!Found)
  1269. Action++;
  1270. }
  1271. }
  1272. if (Found)
  1273. Event = Action;
  1274. else {
  1275. /* check run key */
  1276. if ((key_symbol == RunKeyMap.VirtKey) && (RunKeyMap.ModKey == ModKey))
  1277. Runkey = 1;
  1278. }
  1279. break;
  1280. }
  1281. default:
  1282. break;
  1283. }
  1284. }
  1285. #define MASK_TILES 9
  1286. static int MaskTiles[MASK_TILES][2] = {
  1287. {240, 248}, {241, 249}, {242, 250},
  1288. {243, 251}, {244, 252}, {245, 253},
  1289. {246, 254}, {247, 255}, {TILE_CURSOR1, TILE_CURSOR2}};
  1290. /* =============================================================================
  1291. * FUNCTION: MakeTileMasks
  1292. *
  1293. * DESCRIPTION:
  1294. * This procedure makes the transparency masks for overlay tiles.
  1295. *
  1296. * PARAMETERS:
  1297. *
  1298. * None.
  1299. *
  1300. * RETURN VALUE:
  1301. *
  1302. * None.
  1303. */
  1304. void MakeTileMasks(void) {
  1305. XImage *Image1;
  1306. XImage *Image2;
  1307. XImage *Mask;
  1308. GC gc;
  1309. XGCValues values;
  1310. int Tile;
  1311. int x, y;
  1312. int t1x, t1y;
  1313. int t2x, t2y;
  1314. int p1, p2;
  1315. if (TilePShape == None)
  1316. printf("TilePShape not allocated!\n");
  1317. values.foreground = 1;
  1318. values.background = 0;
  1319. gc = XCreateGC(display, TilePShape, GCForeground | GCBackground, &values);
  1320. for (Tile = 0; Tile < MASK_TILES; Tile++) {
  1321. t1x = (MaskTiles[Tile][0] % 16) * TileWidth;
  1322. t1y = (MaskTiles[Tile][0] / 16) * TileHeight;
  1323. t2x = (MaskTiles[Tile][1] % 16) * TileWidth;
  1324. t2y = (MaskTiles[Tile][1] / 16) * TileHeight;
  1325. Image1 = XGetImage(display, TilePixmap, t1x, t1y, TileWidth, TileHeight,
  1326. 0xffffffff, XYPixmap);
  1327. Image2 = XGetImage(display, TilePixmap, t2x, t2y, TileWidth, TileHeight,
  1328. 0xffffffff, XYPixmap);
  1329. Mask = XGetImage(display, TilePShape, t1x, t1y, TileWidth, TileHeight,
  1330. 0xffffffff, XYPixmap);
  1331. for (y = 0; y < TileHeight; y++) {
  1332. for (x = 0; x < TileWidth; x++) {
  1333. p1 = XGetPixel(Image1, x, y);
  1334. p2 = XGetPixel(Image2, x, y);
  1335. if (p1 != p2)
  1336. XPutPixel(Mask, x, y, 0);
  1337. else
  1338. XPutPixel(Mask, x, y, 1);
  1339. }
  1340. XPutImage(display, TilePShape, gc, Mask, 0, 0, t1x, t1y, TileWidth,
  1341. TileHeight);
  1342. }
  1343. }
  1344. XFreeGC(display, gc);
  1345. }
  1346. /* =============================================================================
  1347. * Exported functions
  1348. */
  1349. /* =============================================================================
  1350. * FUNCTION: init_app
  1351. */
  1352. int init_app(char *DisplayName) {
  1353. int x, y;
  1354. /* XXX trn */
  1355. /*Visual *visual;*/
  1356. int rc;
  1357. char *LoadingText = "Loading data...";
  1358. char *UlarnText = "VLarn";
  1359. XTextProperty xtext;
  1360. display = XOpenDisplay(DisplayName);
  1361. if (display == NULL) {
  1362. fprintf(stderr, "Error: Cannot connect to X server %s\n", DisplayName);
  1363. /*return 0;*/
  1364. exit(1);
  1365. }
  1366. screen_num = DefaultScreen(display);
  1367. white_pixel = WhitePixel(display, screen_num);
  1368. black_pixel = BlackPixel(display, screen_num);
  1369. screen_width = DisplayWidth(display, screen_num);
  1370. screen_height = DisplayHeight(display, screen_num);
  1371. root_window = RootWindow(display, screen_num);
  1372. ularn_window = XCreateSimpleWindow(
  1373. display, root_window, 10, 10, INITIAL_WIDTH, INITIAL_HEIGHT, 2,
  1374. BlackPixel(display, screen_num), WhitePixel(display, screen_num));
  1375. /* Set the window name */
  1376. if (XStringListToTextProperty(&LoadingText, 1, &xtext) == 0) {
  1377. printf("XStringListToTextProperty ran out of memory\n");
  1378. return 0;
  1379. }
  1380. XSetWMName(display, ularn_window, &xtext);
  1381. XFree(xtext.value);
  1382. XMapWindow(display, ularn_window);
  1383. XFlush(display);
  1384. XSync(display, 0);
  1385. /* Create the graphics context */
  1386. gc_values.cap_style = CapButt;
  1387. gc_values.join_style = JoinBevel;
  1388. gc_values_mask = GCCapStyle | GCJoinStyle;
  1389. ularn_gc = XCreateGC(display, ularn_window, gc_values_mask, &gc_values);
  1390. /*
  1391. * Install the menu and set initial check states
  1392. */
  1393. XMENU_SetMenu(display, ularn_window, &Game_Menu, NULL, PaintWindow);
  1394. ularn_menu_height = XMENU_GetMenuHeight();
  1395. if (nobeep)
  1396. XMENU_SetCheck(MENU_DISPLAY_BEEP, XMENU_UNCHECKED);
  1397. else
  1398. XMENU_SetCheck(MENU_DISPLAY_BEEP, XMENU_CHECKED);
  1399. /* Get colours required */
  1400. /*visual = */ DefaultVisual(display, DefaultScreen(display));
  1401. colormap = XDefaultColormap(display, screen_num);
  1402. LtGrey.red = 192 * 256;
  1403. LtGrey.green = 192 * 256;
  1404. LtGrey.blue = 192 * 256;
  1405. XAllocColor(display, colormap, &LtGrey);
  1406. MidGrey.red = 128 * 256;
  1407. MidGrey.green = 128 * 256;
  1408. MidGrey.blue = 128 * 256;
  1409. XAllocColor(display, colormap, &MidGrey);
  1410. DkGrey.red = 96 * 256;
  1411. DkGrey.green = 96 * 256;
  1412. DkGrey.blue = 96 * 256;
  1413. XAllocColor(display, colormap, &DkGrey);
  1414. Red.red = 255 * 256;
  1415. Red.green = 0;
  1416. Red.blue = 0;
  1417. XAllocColor(display, colormap, &Red);
  1418. Green.red = 0;
  1419. Green.green = 128 * 256;
  1420. Green.blue = 0;
  1421. XAllocColor(display, colormap, &Green);
  1422. Blue.red = 0;
  1423. Blue.green = 0;
  1424. Blue.blue = 255 * 256;
  1425. XAllocColor(display, colormap, &Blue);
  1426. font_info = XLoadQueryFont(display, font_name);
  1427. if (!font_info) {
  1428. fprintf(stderr, "Error: XLoadQueryFont: failed loading font '%s'\n",
  1429. font_name);
  1430. return 0;
  1431. }
  1432. XSetFont(display, ularn_gc, font_info->fid);
  1433. XSelectInput(display, ularn_window,
  1434. ExposureMask | KeyPressMask | StructureNotifyMask |
  1435. XMENU_EVENT_MASK);
  1436. CursorPixmap = XCreateBitmapFromData(display, ularn_window, cursor_bits,
  1437. cursor_width, cursor_height);
  1438. TileAttributes.valuemask = XpmCloseness;
  1439. TileAttributes.closeness = 25000;
  1440. rc = XpmReadFileToPixmap(display, ularn_window, TileFilename, &TilePixmap,
  1441. &TilePShape, &TileAttributes);
  1442. if (rc < XpmSuccess) {
  1443. printf("Error reading pixmap: %s\n", XpmGetErrorString(rc));
  1444. printf("Retrying with inferior colours\n");
  1445. TileAttributes.valuemask = XpmCloseness;
  1446. TileAttributes.closeness = 50000;
  1447. rc = XpmReadFileToPixmap(display, ularn_window, TileFilename, &TilePixmap,
  1448. &TilePShape, &TileAttributes);
  1449. if (rc < XpmSuccess)
  1450. printf("Error reading pixmap: %s\n", XpmGetErrorString(rc));
  1451. }
  1452. MakeTileMasks();
  1453. //
  1454. // Clear the text buffers
  1455. //
  1456. for (y = 0; y < MAX_MSG_LINES; y++) {
  1457. for (x = 0; x < LINE_LENGTH; x++) {
  1458. MessageChr[y][x] = ' ';
  1459. MessageFmt[y][x] = FORMAT_NORMAL;
  1460. }
  1461. MessageChr[y][LINE_LENGTH] = 0;
  1462. }
  1463. for (y = 0; y < MAX_TEXT_LINES; y++) {
  1464. for (x = 0; x < LINE_LENGTH; x++) {
  1465. TextChr[y][x] = ' ';
  1466. TextFmt[y][x] = FORMAT_NORMAL;
  1467. }
  1468. TextChr[y][LINE_LENGTH] = 0;
  1469. }
  1470. if (XStringListToTextProperty(&UlarnText, 1, &xtext) == 0) {
  1471. printf("XStringListToTextProperty ran out of memory\n");
  1472. return 0;
  1473. }
  1474. XSetWMName(display, ularn_window, &xtext);
  1475. XFree(xtext.value);
  1476. //
  1477. // Set the initial window size
  1478. //
  1479. CalcMinWindowSize();
  1480. Resize();
  1481. return 1;
  1482. }
  1483. /* =============================================================================
  1484. * FUNCTION: close_app
  1485. */
  1486. void close_app(void) {
  1487. if (TilePixmap != None)
  1488. XFreePixmap(display, TilePixmap);
  1489. if (TilePShape != None)
  1490. XFreePixmap(display, TilePShape);
  1491. if (CursorPixmap != None)
  1492. XFreePixmap(display, CursorPixmap);
  1493. if (ularn_gc != None) {
  1494. XFreeColormap(display, colormap);
  1495. XFreeGC(display, ularn_gc);
  1496. }
  1497. if (ularn_window != None)
  1498. XDestroyWindow(display, ularn_window);
  1499. sleep(4);
  1500. XFlush(display);
  1501. XSync(display, 1);
  1502. if (display != NULL)
  1503. XCloseDisplay(display);
  1504. }
  1505. /* =============================================================================
  1506. * FUNCTION: get_normal_input
  1507. */
  1508. ActionType get_normal_input(void) {
  1509. XEvent xevent; // The X event
  1510. int idx;
  1511. int got_dir;
  1512. Event = ACTION_NULL;
  1513. Runkey = 0;
  1514. while (Event == ACTION_NULL) {
  1515. XNextEvent(display, &xevent);
  1516. handle_event(&xevent);
  1517. //
  1518. // Clear enhanced interface events in enhanced interface is not active
  1519. //
  1520. if (!enhance_interface) {
  1521. if ((Event == ACTION_OPEN_DOOR) || (Event == ACTION_OPEN_CHEST))
  1522. Event = ACTION_NULL;
  1523. }
  1524. }
  1525. if (Runkey) {
  1526. idx = 0;
  1527. got_dir = 0;
  1528. while ((idx < NUM_DIRS) && (!got_dir)) {
  1529. if (DirActions[idx] == Event)
  1530. got_dir = 1;
  1531. else
  1532. idx++;
  1533. }
  1534. if (got_dir)
  1535. /* modify into a run event */
  1536. Event = Event + 1;
  1537. }
  1538. return Event;
  1539. }
  1540. /* =============================================================================
  1541. * FUNCTION: get_prompt_input
  1542. */
  1543. char get_prompt_input(char *prompt, char *answers, int ShowCursor) {
  1544. XEvent xevent; // The X event
  1545. char *ch;
  1546. Print(prompt);
  1547. if (ShowCursor) {
  1548. XSetForeground(display, ularn_gc, black_pixel);
  1549. XSetClipOrigin(display, ularn_gc, TLeft + (CursorX - 1) * CharWidth,
  1550. TTop + (CursorY - 1) * CharHeight + CharAscent);
  1551. XSetClipMask(display, ularn_gc, CursorPixmap);
  1552. XCopyPlane(display, CursorPixmap, ularn_window, ularn_gc, 0, 0,
  1553. cursor_width, cursor_height, TLeft + (CursorX - 1) * CharWidth,
  1554. TTop + (CursorY - 1) * CharHeight + CharAscent, 1);
  1555. XSetClipOrigin(display, ularn_gc, 0, 0);
  1556. XSetClipMask(display, ularn_gc, None);
  1557. CaretActive = 1;
  1558. }
  1559. //
  1560. // Process events until a character in answers has been pressed.
  1561. //
  1562. GotChar = 0;
  1563. while (!GotChar) {
  1564. XNextEvent(display, &xevent);
  1565. handle_event(&xevent);
  1566. if (GotChar) {
  1567. //
  1568. // Search for the input character in the answers string
  1569. //
  1570. ch = strchr(answers, EventChar);
  1571. if (ch == NULL) {
  1572. //
  1573. // Not an answer we want
  1574. //
  1575. GotChar = 0;
  1576. }
  1577. }
  1578. }
  1579. if (ShowCursor) {
  1580. XSetForeground(display, ularn_gc, white_pixel);
  1581. XSetClipOrigin(display, ularn_gc, TLeft + (CursorX - 1) * CharWidth,
  1582. TTop + (CursorY - 1) * CharHeight + CharAscent);
  1583. XSetClipMask(display, ularn_gc, CursorPixmap);
  1584. XCopyPlane(display, CursorPixmap, ularn_window, ularn_gc, 0, 0,
  1585. cursor_width, cursor_height, TLeft + (CursorX - 1) * CharWidth,
  1586. TTop + (CursorY - 1) * CharHeight + CharAscent, 1);
  1587. XSetClipOrigin(display, ularn_gc, 0, 0);
  1588. XSetClipMask(display, ularn_gc, None);
  1589. CaretActive = 0;
  1590. }
  1591. return EventChar;
  1592. }
  1593. /* =============================================================================
  1594. * FUNCTION: get_password_input
  1595. */
  1596. void get_password_input(char *password, int Len) {
  1597. char ch;
  1598. char inputchars[256];
  1599. int Pos;
  1600. int value;
  1601. /* get the printable characters on this system */
  1602. Pos = 0;
  1603. for (value = 0; value < 256; value++) {
  1604. if (isprint(value)) {
  1605. inputchars[Pos] = (char)value;
  1606. Pos++;
  1607. }
  1608. }
  1609. /* add CR, BS and null terminator */
  1610. inputchars[Pos++] = '\010';
  1611. inputchars[Pos++] = '\015';
  1612. inputchars[Pos] = '\0';
  1613. Pos = 0;
  1614. do {
  1615. ch = get_prompt_input("", inputchars, 1);
  1616. if (isprint((int)ch) && (Pos < Len)) {
  1617. password[Pos] = ch;
  1618. Pos++;
  1619. Printc('*');
  1620. } else if (ch == '\010') {
  1621. //
  1622. // Backspace
  1623. //
  1624. if (Pos > 0) {
  1625. CursorX--;
  1626. Printc(' ');
  1627. CursorX--;
  1628. Pos--;
  1629. }
  1630. }
  1631. } while (ch != '\015');
  1632. password[Pos] = 0;
  1633. }
  1634. /* =============================================================================
  1635. * FUNCTION: get_num_input
  1636. */
  1637. int get_num_input(int defval) {
  1638. char ch;
  1639. int Pos = 0;
  1640. int value = 0;
  1641. int neg = 0;
  1642. do {
  1643. ch = get_prompt_input("", "-*0123456789\010\015", 1);
  1644. if ((ch == '-') && (Pos == 0)) {
  1645. //
  1646. // Minus
  1647. //
  1648. neg = 1;
  1649. Printc(ch);
  1650. Pos++;
  1651. }
  1652. if (ch == '*')
  1653. return defval;
  1654. else if (ch == '\010') {
  1655. //
  1656. // Backspace
  1657. //
  1658. if (Pos > 0) {
  1659. if ((Pos == 1) && neg)
  1660. neg = 0;
  1661. else
  1662. value = value / 10;
  1663. CursorX--;
  1664. Printc(' ');
  1665. CursorX--;
  1666. Pos--;
  1667. }
  1668. } else if ((ch >= '0') && (ch <= '9')) {
  1669. //
  1670. // digit
  1671. //
  1672. value = value * 10 + (ch - '0');
  1673. Printc(ch);
  1674. Pos++;
  1675. }
  1676. } while (ch != '\015');
  1677. if (Pos == 0)
  1678. return defval;
  1679. else {
  1680. if (neg)
  1681. value = -value;
  1682. return value;
  1683. }
  1684. }
  1685. /* =============================================================================
  1686. * FUNCTION: get_dir_input
  1687. */
  1688. ActionType get_dir_input(char *prompt, int ShowCursor) {
  1689. XEvent xevent;
  1690. int got_dir;
  1691. int idx;
  1692. //
  1693. // Display the prompt at the current position
  1694. //
  1695. Print(prompt);
  1696. //
  1697. // Show the cursor if required
  1698. //
  1699. if (ShowCursor) {
  1700. XSetForeground(display, ularn_gc, black_pixel);
  1701. XSetClipOrigin(display, ularn_gc, TLeft + (CursorX - 1) * CharWidth,
  1702. TTop + (CursorY - 1) * CharHeight + CharAscent);
  1703. XSetClipMask(display, ularn_gc, CursorPixmap);
  1704. XCopyPlane(display, CursorPixmap, ularn_window, ularn_gc, 0, 0,
  1705. cursor_width, cursor_height, TLeft + (CursorX - 1) * CharWidth,
  1706. TTop + (CursorY - 1) * CharHeight + CharAscent, 1);
  1707. XSetClipOrigin(display, ularn_gc, 0, 0);
  1708. XSetClipMask(display, ularn_gc, None);
  1709. CaretActive = 1;
  1710. }
  1711. Event = ACTION_NULL;
  1712. got_dir = 0;
  1713. while (!got_dir) {
  1714. XNextEvent(display, &xevent);
  1715. handle_event(&xevent);
  1716. idx = 0;
  1717. while ((idx < NUM_DIRS) && (!got_dir)) {
  1718. if (DirActions[idx] == Event)
  1719. got_dir = 1;
  1720. else
  1721. idx++;
  1722. }
  1723. }
  1724. if (ShowCursor) {
  1725. XSetForeground(display, ularn_gc, white_pixel);
  1726. XSetClipOrigin(display, ularn_gc, TLeft + (CursorX - 1) * CharWidth,
  1727. TTop + (CursorY - 1) * CharHeight + CharAscent);
  1728. XSetClipMask(display, ularn_gc, CursorPixmap);
  1729. XCopyPlane(display, CursorPixmap, ularn_window, ularn_gc, 0, 0,
  1730. cursor_width, cursor_height, TLeft + (CursorX - 1) * CharWidth,
  1731. TTop + (CursorY - 1) * CharHeight + CharAscent, 1);
  1732. XSetClipOrigin(display, ularn_gc, 0, 0);
  1733. XSetClipMask(display, ularn_gc, None);
  1734. CaretActive = 0;
  1735. }
  1736. return Event;
  1737. }
  1738. /* =============================================================================
  1739. * FUNCTION: UpdateStatus
  1740. */
  1741. void UpdateStatus(void) {
  1742. if (CurrentDisplayMode == DISPLAY_TEXT)
  1743. /* Don't redisplay if in text mode */
  1744. return;
  1745. PaintStatus();
  1746. }
  1747. /* =============================================================================
  1748. * FUNCTION: UpdateEffects
  1749. */
  1750. void UpdateEffects(void) {
  1751. if (CurrentDisplayMode == DISPLAY_TEXT)
  1752. /* Don't redisplay if in text mode */
  1753. return;
  1754. PaintEffects();
  1755. }
  1756. /* =============================================================================
  1757. * FUNCTION: UpdateStatusAndEffects
  1758. */
  1759. void UpdateStatusAndEffects(void) {
  1760. if (CurrentDisplayMode == DISPLAY_TEXT)
  1761. /* Don't redisplay if in text mode */
  1762. return;
  1763. //
  1764. // Do effects first as update status will mark all effects as current
  1765. //
  1766. PaintEffects();
  1767. PaintStatus();
  1768. }
  1769. /* =============================================================================
  1770. * FUNCTION: set_display
  1771. */
  1772. void set_display(DisplayModeType Mode) {
  1773. //
  1774. // Save the current settings
  1775. //
  1776. if (CurrentDisplayMode == DISPLAY_MAP) {
  1777. MsgCursorX = CursorX;
  1778. MsgCursorY = CursorY;
  1779. CurrentMsgFormat = CurrentFormat;
  1780. } else if (CurrentDisplayMode == DISPLAY_TEXT) {
  1781. TextCursorX = CursorX;
  1782. TextCursorY = CursorY;
  1783. CurrentTextFormat = CurrentFormat;
  1784. }
  1785. CurrentDisplayMode = Mode;
  1786. //
  1787. // Set the text buffer settings for the new display mode
  1788. //
  1789. if (CurrentDisplayMode == DISPLAY_MAP) {
  1790. CursorX = MsgCursorX;
  1791. CursorY = MsgCursorY;
  1792. CurrentFormat = CurrentMsgFormat;
  1793. Text = MessageChr;
  1794. Format = MessageFmt;
  1795. MaxLine = MAX_MSG_LINES;
  1796. TLeft = MessageLeft;
  1797. TTop = MessageTop;
  1798. TWidth = MessageWidth;
  1799. THeight = MessageHeight;
  1800. } else if (CurrentDisplayMode == DISPLAY_TEXT) {
  1801. CursorX = TextCursorX;
  1802. CursorY = TextCursorY;
  1803. CurrentFormat = CurrentTextFormat;
  1804. Text = TextChr;
  1805. Format = TextFmt;
  1806. MaxLine = MAX_TEXT_LINES;
  1807. TLeft = TextLeft;
  1808. TTop = TextTop;
  1809. TWidth = TextWidth;
  1810. THeight = TextHeight;
  1811. }
  1812. PaintWindow();
  1813. }
  1814. /* =============================================================================
  1815. * FUNCTION: IncCursorY
  1816. *
  1817. * DESCRIPTION:
  1818. * Increae the cursor y position, scrolling the text window if requried.
  1819. *
  1820. * PARAMETERS:
  1821. *
  1822. * Count : The number of lines to increase the cursor y position
  1823. *
  1824. * RETURN VALUE:
  1825. *
  1826. * None.
  1827. */
  1828. static void IncCursorY(int Count) {
  1829. int Scroll;
  1830. int inc;
  1831. int Line;
  1832. int x;
  1833. inc = Count;
  1834. Scroll = 0;
  1835. while (inc > 0) {
  1836. CursorY = CursorY + 1;
  1837. if (CursorY > MaxLine) {
  1838. Scroll = 1;
  1839. for (Line = 0; Line < (MaxLine - 1); Line++) {
  1840. for (x = 0; x < LINE_LENGTH; x++) {
  1841. Text[Line][x] = Text[Line + 1][x];
  1842. Format[Line][x] = Format[Line + 1][x];
  1843. }
  1844. }
  1845. CursorY--;
  1846. for (x = 0; x < LINE_LENGTH; x++) {
  1847. Text[MaxLine - 1][x] = ' ';
  1848. Format[MaxLine - 1][x] = FORMAT_NORMAL;
  1849. }
  1850. }
  1851. inc--;
  1852. }
  1853. if (Scroll)
  1854. PaintTextWindow();
  1855. }
  1856. /* =============================================================================
  1857. * FUNCTION: IncCursorX
  1858. *
  1859. * DESCRIPTION:
  1860. * Increase the cursor x position, handling line wrap.
  1861. *
  1862. * PARAMETERS:
  1863. *
  1864. * Count : The amount to increase the cursor x position.
  1865. *
  1866. * RETURN VALUE:
  1867. *
  1868. * None.
  1869. */
  1870. static void IncCursorX(int Count) {
  1871. CursorX = CursorX + Count;
  1872. if (CursorX > LINE_LENGTH) {
  1873. CursorX = 1;
  1874. IncCursorY(1);
  1875. }
  1876. }
  1877. /* =============================================================================
  1878. * FUNCTION: ClearText
  1879. */
  1880. void ClearText(void) {
  1881. int x, y;
  1882. //
  1883. // Clear the text buffer
  1884. //
  1885. for (y = 0; y < MaxLine; y++) {
  1886. for (x = 0; x < LINE_LENGTH; x++) {
  1887. Text[y][x] = ' ';
  1888. Format[y][x] = FORMAT_NORMAL;
  1889. }
  1890. Text[y][LINE_LENGTH] = 0;
  1891. }
  1892. CursorX = 1;
  1893. CursorY = 1;
  1894. //
  1895. // Clear the text area
  1896. //
  1897. PaintTextWindow();
  1898. XFlush(display);
  1899. XSync(display, 0);
  1900. }
  1901. /* =============================================================================
  1902. * FUNCTION: UlarnBeep
  1903. */
  1904. void UlarnBeep(void) {
  1905. //
  1906. // Middle C, 1/4 second
  1907. //
  1908. if (!nobeep)
  1909. XBell(display, 100);
  1910. }
  1911. /* =============================================================================
  1912. * FUNCTION: Cursor
  1913. */
  1914. void MoveCursor(int x, int y) {
  1915. CursorX = x;
  1916. CursorY = y;
  1917. }
  1918. /* =============================================================================
  1919. * FUNCTION: Printc
  1920. */
  1921. void Printc(char c) {
  1922. int incx;
  1923. char lc;
  1924. switch (c) {
  1925. case '\t':
  1926. incx = ((((CursorX - 1) / 8) + 1) * 8 + 1) - CursorX;
  1927. IncCursorX(incx);
  1928. break;
  1929. case '\n':
  1930. CursorX = 1;
  1931. IncCursorY(1);
  1932. break;
  1933. case '\015':
  1934. break;
  1935. default:
  1936. lc = Text[CursorY - 1][CursorX - 1];
  1937. if (lc != c) {
  1938. /* Erase the char that was here */
  1939. XSetForeground(display, ularn_gc, white_pixel);
  1940. XSetBackground(display, ularn_gc, black_pixel);
  1941. XSetFillStyle(display, ularn_gc, FillSolid);
  1942. XFillRectangle(display, ularn_window, ularn_gc,
  1943. TLeft + (CursorX - 1) * CharWidth,
  1944. TTop + (CursorY - 1) * CharHeight, CharWidth, CharHeight);
  1945. }
  1946. Text[CursorY - 1][CursorX - 1] = c;
  1947. Format[CursorY - 1][CursorX - 1] = CurrentFormat;
  1948. switch (CurrentFormat) {
  1949. case FORMAT_NORMAL:
  1950. XSetForeground(display, ularn_gc, black_pixel);
  1951. break;
  1952. case FORMAT_STANDOUT:
  1953. XSetForeground(display, ularn_gc, Red.pixel);
  1954. break;
  1955. case FORMAT_STANDOUT2:
  1956. XSetForeground(display, ularn_gc, Green.pixel);
  1957. break;
  1958. case FORMAT_STANDOUT3:
  1959. XSetForeground(display, ularn_gc, Blue.pixel);
  1960. break;
  1961. default:
  1962. break;
  1963. }
  1964. XDrawString(display, ularn_window, ularn_gc,
  1965. TLeft + (CursorX - 1) * CharWidth,
  1966. TTop + (CursorY - 1) * CharHeight + CharAscent, &c, 1);
  1967. IncCursorX(1);
  1968. break;
  1969. }
  1970. }
  1971. /* =============================================================================
  1972. * FUNCTION: Print
  1973. */
  1974. void Print(char *string) {
  1975. int Len;
  1976. int pos;
  1977. if (string == NULL)
  1978. return;
  1979. Len = strlen(string);
  1980. if (Len == 0)
  1981. return;
  1982. for (pos = 0; pos < Len; pos++)
  1983. Printc(string[pos]);
  1984. XFlush(display);
  1985. XSync(display, 0);
  1986. }
  1987. /* =============================================================================
  1988. * FUNCTION: Printf
  1989. */
  1990. void Printf(char *fmt, ...) {
  1991. char buf[2048];
  1992. va_list argptr;
  1993. va_start(argptr, fmt);
  1994. vsprintf(buf, fmt, argptr);
  1995. va_end(argptr);
  1996. Print(buf);
  1997. }
  1998. /* =============================================================================
  1999. * FUNCTION: Standout
  2000. */
  2001. void Standout(char *String) {
  2002. CurrentFormat = FORMAT_STANDOUT;
  2003. Print(String);
  2004. CurrentFormat = FORMAT_NORMAL;
  2005. }
  2006. /* =============================================================================
  2007. * FUNCTION: SetFormat
  2008. */
  2009. void SetFormat(FormatType format) { CurrentFormat = format; }
  2010. /* =============================================================================
  2011. * FUNCTION: ClearToEOL
  2012. */
  2013. void ClearToEOL(void) {
  2014. int x;
  2015. for (x = CursorX; x <= LINE_LENGTH; x++) {
  2016. Text[CursorY - 1][x - 1] = ' ';
  2017. Format[CursorY - 1][x - 1] = FORMAT_NORMAL;
  2018. }
  2019. XSetForeground(display, ularn_gc, white_pixel);
  2020. XSetBackground(display, ularn_gc, black_pixel);
  2021. XSetFillStyle(display, ularn_gc, FillSolid);
  2022. XFillRectangle(display, ularn_window, ularn_gc,
  2023. TLeft + (CursorX - 1) * CharWidth,
  2024. TTop + (CursorY - 1) * CharHeight,
  2025. ((LINE_LENGTH - CursorX) + 1) * CharWidth, CharHeight);
  2026. }
  2027. /* =============================================================================
  2028. * FUNCTION: ClearToEOPage
  2029. */
  2030. void ClearToEOPage(int x, int y) {
  2031. int tx, ty;
  2032. for (tx = x; tx <= LINE_LENGTH; tx++) {
  2033. Text[y - 1][tx - 1] = ' ';
  2034. Format[y - 1][tx - 1] = FORMAT_NORMAL;
  2035. }
  2036. XSetForeground(display, ularn_gc, white_pixel);
  2037. XSetBackground(display, ularn_gc, black_pixel);
  2038. XSetFillStyle(display, ularn_gc, FillSolid);
  2039. XFillRectangle(display, ularn_window, ularn_gc, TLeft + (x - 1) * CharWidth,
  2040. TTop + (y - 1) * CharHeight,
  2041. ((LINE_LENGTH - x) + 1) * CharWidth, CharHeight);
  2042. for (ty = y + 1; ty <= MaxLine; ty++) {
  2043. for (tx = 1; tx <= LINE_LENGTH; tx++) {
  2044. Text[ty - 1][tx - 1] = ' ';
  2045. Format[ty - 1][tx - 1] = FORMAT_NORMAL;
  2046. }
  2047. XFillRectangle(display, ularn_window, ularn_gc, TLeft,
  2048. TTop + (ty - 1) * CharHeight, LINE_LENGTH * CharWidth,
  2049. CharHeight);
  2050. }
  2051. }
  2052. /* =============================================================================
  2053. * FUNCTION: show1cell
  2054. */
  2055. void show1cell(int x, int y) {
  2056. int TileId;
  2057. int sx, sy;
  2058. int TileX, TileY;
  2059. /* see nothing if blind */
  2060. if (c[BLINDCOUNT])
  2061. return;
  2062. /* we end up knowing about it */
  2063. know[x][y] = item[x][y];
  2064. if (mitem[x][y].mon != MONST_NONE)
  2065. stealth[x][y] |= STEALTH_SEEN;
  2066. sx = x - MapTileLeft;
  2067. sy = y - MapTileTop;
  2068. if ((sx < 0) || (sx >= MapTileWidth) || (sy < 0) || (sy >= MapTileHeight)) {
  2069. //
  2070. // Tile is not currently in the visible part of the map,
  2071. // so don't draw anything
  2072. //
  2073. return;
  2074. }
  2075. GetTile(x, y, &TileId);
  2076. TileX = (TileId % 16) * TileWidth;
  2077. TileY = (TileId / 16) * TileHeight;
  2078. XCopyArea(display, TilePixmap, ularn_window, ularn_gc, TileX, TileY,
  2079. TileWidth, TileHeight, MapLeft + sx * TileWidth,
  2080. MapTop + sy * TileHeight);
  2081. }
  2082. /* =============================================================================
  2083. * FUNCTION: showplayer
  2084. */
  2085. void showplayer(void) {
  2086. int sx, sy;
  2087. int TileId;
  2088. int TileX, TileY;
  2089. int scroll;
  2090. //
  2091. // Determine if we need to scroll the map
  2092. //
  2093. scroll = calc_scroll();
  2094. if (scroll)
  2095. PaintMap();
  2096. else {
  2097. sx = playerx - MapTileLeft;
  2098. sy = playery - MapTileTop;
  2099. if ((sx >= 0) && (sx < MapTileWidth) && (sy >= 0) && (sy < MapTileHeight)) {
  2100. if (c[BLINDCOUNT] == 0)
  2101. TileId = PlayerTiles[class_num][(int)sex];
  2102. else
  2103. GetTile(playerx, playery, &TileId);
  2104. TileX = (TileId % 16) * TileWidth;
  2105. TileY = (TileId / 16) * TileHeight;
  2106. XCopyArea(display, TilePixmap, ularn_window, ularn_gc, TileX, TileY,
  2107. TileWidth, TileHeight, MapLeft + sx * TileWidth,
  2108. MapTop + sy * TileHeight);
  2109. TileId = TILE_CURSOR1;
  2110. TileX = (TileId % 16) * TileWidth;
  2111. TileY = (TileId / 16) * TileHeight;
  2112. XSetClipOrigin(display, ularn_gc, MapLeft + sx * TileWidth - TileX,
  2113. MapTop + sy * TileHeight - TileY);
  2114. XSetClipMask(display, ularn_gc, TilePShape);
  2115. XCopyArea(display, TilePixmap, ularn_window, ularn_gc, TileX, TileY,
  2116. TileWidth, TileHeight, MapLeft + sx * TileWidth,
  2117. MapTop + sy * TileHeight);
  2118. XSetClipOrigin(display, ularn_gc, 0, 0);
  2119. XSetClipMask(display, ularn_gc, None);
  2120. } /* If player on visible map area */
  2121. }
  2122. }
  2123. /* =============================================================================
  2124. * FUNCTION: showcell
  2125. */
  2126. void showcell(int x, int y) {
  2127. int minx, maxx;
  2128. int miny, maxy;
  2129. int mx, my;
  2130. int sx, sy;
  2131. int TileX, TileY;
  2132. int TileId;
  2133. int scroll;
  2134. //
  2135. // Determine if we need to scroll the map
  2136. //
  2137. scroll = calc_scroll();
  2138. /*
  2139. * Decide how much the player knows about around him/her.
  2140. */
  2141. if (c[AWARENESS]) {
  2142. minx = x - 3;
  2143. maxx = x + 3;
  2144. miny = y - 3;
  2145. maxy = y + 3;
  2146. } else {
  2147. minx = x - 1;
  2148. maxx = x + 1;
  2149. miny = y - 1;
  2150. maxy = y + 1;
  2151. }
  2152. if (c[BLINDCOUNT]) {
  2153. minx = x;
  2154. maxx = x;
  2155. miny = y;
  2156. maxy = y;
  2157. //
  2158. // Redraw the last player position to remove the cursor
  2159. //
  2160. if (!scroll) {
  2161. //
  2162. // Only redraw if the map is not going to be completely redrawn.
  2163. //
  2164. sx = lastpx - MapTileLeft;
  2165. sy = lastpy - MapTileTop;
  2166. if ((sx >= 0) && (sx < MapTileWidth) && (sy >= 0) &&
  2167. (sy < MapTileHeight)) {
  2168. //
  2169. // Tile is currently visible, so draw it
  2170. //
  2171. GetTile(lastpx, lastpy, &TileId);
  2172. TileX = (TileId % 16) * TileWidth;
  2173. TileY = (TileId / 16) * TileHeight;
  2174. XCopyArea(display, TilePixmap, ularn_window, ularn_gc, TileX, TileY,
  2175. TileWidth, TileHeight, MapLeft + sx * TileWidth,
  2176. MapTop + sy * TileHeight);
  2177. }
  2178. }
  2179. }
  2180. /*
  2181. * Limit the area to the map extents
  2182. */
  2183. if (minx < 0)
  2184. minx = 0;
  2185. if (maxx > MAXX - 1)
  2186. maxx = MAXX - 1;
  2187. if (miny < 0)
  2188. miny = 0;
  2189. if (maxy > MAXY - 1)
  2190. maxy = MAXY - 1;
  2191. for (my = miny; my <= maxy; my++) {
  2192. for (mx = minx; mx <= maxx; mx++) {
  2193. if ((mx == playerx) && (my == playery)) {
  2194. know[mx][my] = item[mx][my];
  2195. if (!scroll) {
  2196. //
  2197. // Only draw if the entire map is not going to be scrolled
  2198. //
  2199. showplayer();
  2200. }
  2201. } else if ((know[mx][my] != item[mx][my]) || /* item changed */
  2202. ((mx == lastpx) && (my == lastpy)) || /* last player pos */
  2203. ((mitem[mx][my].mon != MONST_NONE) && /* unseen monster */
  2204. ((stealth[mx][my] & STEALTH_SEEN) == 0))) {
  2205. //
  2206. // Only draw areas not already known (and hence displayed)
  2207. //
  2208. know[mx][my] = item[mx][my];
  2209. if (mitem[mx][my].mon != MONST_NONE)
  2210. stealth[mx][my] |= STEALTH_SEEN;
  2211. if (!scroll) {
  2212. //
  2213. // Only draw the tile if the map is not going to be scrolled
  2214. //
  2215. sx = mx - MapTileLeft;
  2216. sy = my - MapTileTop;
  2217. if ((sx >= 0) && (sx < MapTileWidth) && (sy >= 0) &&
  2218. (sy < MapTileHeight)) {
  2219. //
  2220. // Tile is currently visible, so draw it
  2221. //
  2222. GetTile(mx, my, &TileId);
  2223. TileX = (TileId % 16) * TileWidth;
  2224. TileY = (TileId / 16) * TileHeight;
  2225. XCopyArea(display, TilePixmap, ularn_window, ularn_gc, TileX, TileY,
  2226. TileWidth, TileHeight, MapLeft + sx * TileWidth,
  2227. MapTop + sy * TileHeight);
  2228. }
  2229. }
  2230. } // if not known
  2231. }
  2232. }
  2233. if (scroll)
  2234. /* scrolling the map window, so repaint everything and return */
  2235. PaintMap();
  2236. }
  2237. /* =============================================================================
  2238. * FUNCTION: drawscreen
  2239. */
  2240. void drawscreen(void) { PaintWindow(); }
  2241. /* =============================================================================
  2242. * FUNCTION: draws
  2243. */
  2244. void draws(int minx, int miny, int maxx, int maxy) { PaintWindow(); }
  2245. /* =============================================================================
  2246. * FUNCTION: mapeffect
  2247. */
  2248. void mapeffect(int x, int y, DirEffectsType effect, int dir) {
  2249. int TileId;
  2250. int sx, sy;
  2251. int TileX, TileY;
  2252. /* see nothing if blind */
  2253. if (c[BLINDCOUNT])
  2254. return;
  2255. sx = x - MapTileLeft;
  2256. sy = y - MapTileTop;
  2257. if ((sx < 0) || (sx >= MapTileWidth) || (sy < 0) || (sy >= MapTileHeight)) {
  2258. //
  2259. // Tile is not currently in the visible part of the map,
  2260. // so don't draw anything
  2261. //
  2262. return;
  2263. }
  2264. TileId = EffectTile[effect][dir];
  2265. TileX = (TileId % 16) * TileWidth;
  2266. TileY = (TileId / 16) * TileHeight;
  2267. XCopyArea(display, TilePixmap, ularn_window, ularn_gc, TileX, TileY,
  2268. TileWidth, TileHeight, MapLeft + sx * TileWidth,
  2269. MapTop + sy * TileHeight);
  2270. }
  2271. /* =============================================================================
  2272. * FUNCTION: magic_effect_frames
  2273. */
  2274. int magic_effect_frames(MagicEffectsType fx) { return magicfx_tile[fx].Frames; }
  2275. /* =============================================================================
  2276. * FUNCTION: magic_effect
  2277. */
  2278. void magic_effect(int x, int y, MagicEffectsType fx, int frame) {
  2279. int TileId;
  2280. int sx, sy;
  2281. int TileX, TileY;
  2282. if (frame > magicfx_tile[fx].Frames)
  2283. return;
  2284. /*
  2285. * draw the tile that is at this location
  2286. */
  2287. /* see nothing if blind */
  2288. if (c[BLINDCOUNT])
  2289. return;
  2290. sx = x - MapTileLeft;
  2291. sy = y - MapTileTop;
  2292. if ((sx < 0) || (sx >= MapTileWidth) || (sy < 0) || (sy >= MapTileHeight)) {
  2293. //
  2294. // Tile is not currently in the visible part of the map,
  2295. // so don't draw anything
  2296. //
  2297. return;
  2298. }
  2299. if (magicfx_tile[fx].Overlay) {
  2300. GetTile(x, y, &TileId);
  2301. TileX = (TileId % 16) * TileWidth;
  2302. TileY = (TileId / 16) * TileHeight;
  2303. XCopyArea(display, TilePixmap, ularn_window, ularn_gc, TileX, TileY,
  2304. TileWidth, TileHeight, MapLeft + sx * TileWidth,
  2305. MapTop + sy * TileHeight);
  2306. TileId = magicfx_tile[fx].Tile1[frame];
  2307. TileX = (TileId % 16) * TileWidth;
  2308. TileY = (TileId / 16) * TileHeight;
  2309. XSetClipOrigin(display, ularn_gc, MapLeft + sx * TileWidth - TileX,
  2310. MapTop + sy * TileHeight - TileY);
  2311. XSetClipMask(display, ularn_gc, TilePShape);
  2312. XCopyArea(display, TilePixmap, ularn_window, ularn_gc, TileX, TileY,
  2313. TileWidth, TileHeight, MapLeft + sx * TileWidth,
  2314. MapTop + sy * TileHeight);
  2315. XSetClipOrigin(display, ularn_gc, 0, 0);
  2316. XSetClipMask(display, ularn_gc, None);
  2317. } else {
  2318. TileId = magicfx_tile[fx].Tile1[frame];
  2319. TileX = (TileId % 16) * TileWidth;
  2320. TileY = (TileId / 16) * TileHeight;
  2321. XCopyArea(display, TilePixmap, ularn_window, ularn_gc, TileX, TileY,
  2322. TileWidth, TileHeight, MapLeft + sx * TileWidth,
  2323. MapTop + sy * TileHeight);
  2324. }
  2325. }
  2326. /* =============================================================================
  2327. * FUNCTION: nap
  2328. */
  2329. void nap(int delay) {
  2330. XFlush(display);
  2331. XSync(display, 0);
  2332. usleep(delay * 1000);
  2333. }
  2334. /* =============================================================================
  2335. * FUNCTION: GetUser
  2336. */
  2337. void GetUser(char *username, int *uid) {
  2338. *uid = getuid();
  2339. strcpy(username, getenv("USER"));
  2340. }